Quick start
From an existing Next.js app to a live deployment, one command at a time.
Every stage is its own command, so a failure can be re-run in isolation without repeating the stages that already succeeded.
1. Look before you build#
cd your-nextjs-app
nextship detect> Inspecting project
v acme-web is a Next.js 16.2.9 project
root C:\Users\you\projects\acme-web
package mgr pnpm
build command pnpm run build
node 24
sharp 0.34.5
env files noneEverything reported is read from disk rather than from what package.json declares,
including packages your package manager installed transitively. A project with no env
files says so, instead of leaving you to guess.
In a workspace it also reports the workspace root and the app directory, because the image is built from the workspace root where the lockfile and sibling manifests live.
2. Find out what changes#
nextship doctorThis reports what stops working when an app leaves a managed platform. Most of it never
blocks a build, which is exactly why it is worth surfacing: no error would ever reveal it.
The one blocker it does report is a package installed in node_modules that nothing
declares, because that fails the build inside the image.
Findings are sorted with blockers first, and each carries a consequence and an action rather than only a name.
3. Run it locally first#
nextship runBuilds, packages and starts the image on port 3000, loading your highest-precedence env file so secrets stay outside the image. This exists so the artifact can be verified before any cloud account is involved.
It runs attached with --rm. Ctrl+C stops and removes the container, so there is no
background state to clean up. A stop is reported as a stop rather than a failure: exit 130
for Ctrl+C and 143 for docker stop are the codes Next.js exits with after draining
connections.
4. Deploy to your own server#
Any Ubuntu 22.04, Ubuntu 24.04 or Debian 12 server you can reach over SSH, as root or a user with passwordless sudo. No cloud token is involved.
nextship server add root@203.0.113.10 # the setup plan and the host key fingerprint
nextship server add root@203.0.113.10 --yes # prepare the server and record it
nextship deploy # prints the plan, changes nothing
nextship deploy --yes # executes itCompare the fingerprint in the plan with the one your provider shows before you pass
--yes: from then on, a server presenting any other key is refused. The plan is printed
every time, and nothing on the server changes until --yes.
server add records the server in nextship.json:
{
"version": 2,
"target": "vm",
"name": "acme-web",
"server": {
"host": "203.0.113.10",
"port": 22,
"user": "nextship",
"hostKey": "203.0.113.10 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOAcvH/9nWZZCMAtztAmv9Rm8tknstGlFBaWtrS+QjI1",
"arch": "arm64"
}
}Commit that file. It holds no secrets, only the server's public host key. It is how every later command knows which server and app belong to this project. Your own server covers what setup changes and what stays yours to run.
Or to DigitalOcean App Platform#
A managed platform instead of a server you run: set a token, and deploy creates the app.
export DIGITALOCEAN_TOKEN=dop_v1_...
nextship deploy # prints the plan, changes nothing
nextship deploy --yes # executes itOn the first deploy nextship records the app name, region and registry in nextship.json,
which is the only reason destroy can be certain it will not touch anything else in your
account. Deploying to App Platform covers the rest.
Tell us how it went#
Every verification so far was run by the people who wrote nextship. If you deployed something, or got stuck trying, a first deploy report takes two minutes and is the most useful thing anyone can contribute right now, including when everything worked.
Where to go next#
- Your own server for the server target: setup, deploying, and keeping it running
- Deploying to App Platform for the plan and how a release is verified there
- Environment variables for pushing secrets safely
- Custom domains for attaching a domain with automatic TLS
- Rollbacks and logs for when something goes wrong

