AirLink
Blog

What's coming: Next.js migration, UI overhaul, and the path ahead

thavanish · Wed Apr 01 2026 00:00:00 GMT+0000 (Coordinated Universal Time) · 5 min read
Airlink

We're being transparent about where Airlink is right now, what's actively being built, and what's planned for the rest of the year. This covers the full picture — the migration, the redesign, the API rework, and the longer-term daemon rewrite.


Where things stand

Airlink has been running on an Express + EJS stack since its first release. It works. Servers run, nodes connect, the panel does what it's supposed to do. But the codebase has accumulated the kind of debt that makes adding features slower than it should be — tightly coupled routes, EJS templates with scattered inline logic, and a frontend that has no real component model.

The decision to move to Next.js wasn't about chasing trends. It's because the panel needs a proper foundation before we can do the things we actually want to do: a better UI, a standalone API layer, proper testing, and eventually a daemon that doesn't depend on Node.js bindings.

Here's where each part of the migration sits right now:

Next.js migration status
Auth systemdone
Server management pagesdone
Admin paneldone
WebSocket console proxydone
SFTP + backup managementdone
Folder systemdone
Addon systempartial
Theming + translationsin progress
Radar (VirusTotal)in progress
Player stats collectorpartial
Security hardeningpartial

Phase 1 — Next.js migration

Target: end of this week

The goal is a clean 1:1 port. Every feature the Express panel had, the Next.js panel has. No regressions, no cut corners. We're not shipping a "mostly working" migration — it either matches or it doesn't ship.

What's already running in the new stack:

  • Full auth with login rate limiting, account lockout, and login history
  • All server management pages: console, file manager, backups, worlds, players, startup config, settings
  • Full admin panel: nodes, servers, users, images, API keys, settings, analytics, addons
  • WebSocket console proxy running through a custom server.ts alongside Next.js
  • On-demand SFTP credential management
  • Folder system for grouping servers
  • User account management including avatar uploads

What's left before we call it done:

The addon system port is roughly 70% there. The Express addon handler was fairly coupled to the EJS rendering pipeline — we're rewriting it to work cleanly with Next.js API routes. Theming and translations are partially implemented; the variable system is in place but the theme switcher UI and language loading need to land. Radar is the most straightforward remaining piece — it's a VirusTotal API wrapper and the route logic is already written, it just needs plugging in. Player stats collector needs a cron-equivalent in Next.js (we're using a lightweight interval-based approach rather than a proper job queue for now). Security hardening is mostly done — rate limiting and session options are wired up, still reviewing a few edge cases in the CSRF story for the new stack.


Phase 2 — UI overhaul + modular API

Target: end of May 2026

Two things happen in parallel once the migration is locked.

UI overhaul

The current UI was designed to match the Express panel 1:1 — it was never meant to be the final look. Phase 2 is a proper redesign built on the new stack.

What's changing:

  • Component library: shadcn/ui as the base. Not used wholesale — components get adapted to match the product's design language, not the other way around.
  • Dark mode: the current dark mode works but it was retrofitted. The new design treats dark as the primary mode and derives the light theme from it, not the reverse.
  • Mobile: the current panel is desktop-first. The new one is designed mobile-first. Server console, file manager, and the dashboard all need real mobile layouts, not just scaled-down desktop ones.
  • Typography and spacing: moving to a deliberate type scale and spacing system. No more arbitrary pixel values scattered through inline styles.
  • Admin panel: the admin panel is getting a layout rework. The current grid of cards is being replaced with a proper data-dense layout that shows more without feeling cluttered.

Here's a rough sense of the scope by section:

UI overhaul scope by section

Dashboard
90%
Server console
85%
File manager
80%
Admin panel
70%
Node management
65%
Settings
60%
Auth pages
95%

Modular API

Right now every API route lives inside the panel repo under src/app/api/. That works fine for a monolith but makes it hard to version, test independently, or reuse outside the panel.

We're extracting the API layer into a separate package pulled into the panel as a git submodule. The structure looks like this:

airlink-api/
  src/
    admin/     — node, server, user, image, settings routes
    user/      — account, folder, server routes
    server/    — per-server ops: console, files, backups, startup, worlds
    auth/      — login, logout, register, session
  shared/
    session.ts
    prisma.ts
    validators.ts

Each group is independently versioned. The panel pins a specific ref. If something needs to change in the API — say, a breaking change to the server routes — it can be reviewed and merged in isolation without touching the panel repo.

This also means third-party integrations and future tooling (CLI, mobile app, whatever) can consume the same API package without duplicating logic.


Phase 3 — Daemon Rust port

Status: planning, not started. No timeline yet.

The daemon is the process that runs on each node and does the actual work — spinning up Docker containers, managing file operations through native C++ bindings, handling SFTP sessions, proxying WebSocket connections to running instances. It's currently TypeScript on Express.

The plan is to rewrite it in Rust. The reasons:

  • The native bindings (secure_open.cc, rename_at.cc) are already C++ — Rust fits this layer better than Node.js wrappers
  • Single binary deployment with no Node.js runtime dependency on nodes
  • Better memory safety for the file operation layer specifically — the current C++ binding for secure_open has edge cases we don't fully trust
  • Async I/O in Rust (tokio) will handle concurrent container connections more efficiently than Node.js at scale

This doesn't start until Phase 2 is wrapped up. We'll post a proper design doc when we're ready to start planning the implementation.


Following along

Everything is open source at github.com/AirlinkLabs/panel. Issues, PRs, and feedback are welcome. We post updates here when phases ship.

All posts