Before you begin
Install Node.js 20 or newer, npm, Git, and the Adios CLI. You will also need an Adios account and a Git repository destination if you want to push the finished source.
Create the Next.js project
This command makes the choices explicit: TypeScript, Tailwind, ESLint, App Router, a src directory, the default import alias, and npm.
npx create-next-app@latest ./my-project \
--ts \
--tailwind \
--eslint \
--app \
--src-dir \
--import-alias "@/*" \
--use-npm
cd my-project
npm run devOpen http://localhost:3000 and confirm the starter page loads. Stop the development server before continuing if you want to reuse the terminal.
Replace the starter page
Replace src/app/page.tsx with a small server-rendered page. Keeping metadata in the page makes the example complete without changing the generated root layout.
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Northstar — A small app ready to ship",
description:
"A production-ready Next.js example with health and search metadata routes.",
};
const checks = [
"Responsive App Router page",
"Production health endpoint",
"Sitemap and robots routes",
"Repeatable Adios deployment",
];
export default function Home() {
return (
<main className="min-h-screen bg-slate-950 px-6 py-20 text-white">
<div className="mx-auto max-w-5xl">
<p className="text-sm font-semibold uppercase tracking-[0.18em] text-cyan-300">
Next.js on Adios
</p>
<h1 className="mt-5 max-w-3xl text-5xl font-bold tracking-tight sm:text-7xl">
Build the app. Keep the deployment clear.
</h1>
<p className="mt-6 max-w-2xl text-lg leading-8 text-slate-300">
This project has the files a production release needs, from a health
check to the runtime contract stored beside the source.
</p>
<div className="mt-12 grid gap-4 sm:grid-cols-2">
{checks.map((check) => (
<div
key={check}
className="rounded-xl border border-white/10 bg-white/5 p-5 text-base text-slate-200"
>
{check}
</div>
))}
</div>
<a
href="/api/health"
className="mt-10 inline-flex rounded-lg bg-white px-5 py-3 font-semibold text-slate-950"
>
Check application health
</a>
</div>
</main>
);
}Create the health route
Add src/app/api/health/route.ts. Adios will request this route before it promotes the candidate release.
export function GET() {
return Response.json({ status: "ok" });
}Keep this route fast. If your application cannot serve traffic without a database or another required service, decide whether readiness should verify that dependency too.
Add sitemap and robots routes
Next.js metadata files generate the public /sitemap.xmland /robots.txt responses. The local fallback keeps development working; production should use the final public URL.
import type { MetadataRoute } from "next";
const siteUrl =
process.env.NEXT_PUBLIC_SITE_URL ?? "http://localhost:3000";
export default function sitemap(): MetadataRoute.Sitemap {
return [
{
url: siteUrl + "/",
lastModified: new Date(),
changeFrequency: "weekly",
priority: 1,
},
];
}import type { MetadataRoute } from "next";
const siteUrl =
process.env.NEXT_PUBLIC_SITE_URL ?? "http://localhost:3000";
export default function robots(): MetadataRoute.Robots {
return {
rules: {
userAgent: "*",
allow: "/",
},
sitemap: siteUrl + "/sitemap.xml",
};
}Create adios.yaml in the project root
This file belongs beside package.json. It records how Adios should install, build, start, and check the current project.
name: my-nextjs-app
region: de
replicas: 1
build_cmd: npm ci && npm run build
start_cmd: npm start
env:
NEXT_PUBLIC_SITE_URL: https://replace-with-your-route.adios.run
runtime:
name: node@24
port: 3000
health_path: /api/health
memory_mb: 1024Keep the placeholder hostname for the first deployment. Once Adios returns the generated route, replace it with the real HTTPS origin and deploy again so the sitemap contains the correct URL.
Run the production checks locally
A development page loading is not enough. Run the linter and the same production build the deployment will use.
npm run lint
npm run buildIf either command fails, fix the first error and rerun both checks before deploying.
Sign in and deploy the current source
Run the commands from the directory that contains adios.yaml. Review any requested permissions before allowing the deployment to continue.
adios login
adios upAdios uploads the current source, runs the build, starts the production process, checks /api/health, and returns a generated HTTPS route after the release is healthy.
Visit and verify the production app
Open the generated hostname and check all four responses:
/renders the new page./api/healthreturns{"status":"ok"}./robots.txtallows crawling and names the sitemap./sitemap.xmlcontains the public production URL.
Replace the placeholder NEXT_PUBLIC_SITE_URL value in adios.yaml with the generated hostname or your custom domain, run adios up again, and repeat the checks. Use Domains and Redirects when attaching a production hostname.
Review, commit, and push the working source
Review what changed before creating history. The diff should show the page, health route, search metadata routes, and manifest you just verified.
git status
git diff
git add src/app/page.tsx src/app/api/health/route.ts \
src/app/sitemap.ts src/app/robots.ts adios.yaml
git diff --cached
git commit -m "Build and deploy the Next.js app"
git remote -v
git push -u origin mainConfirm the remote and branch before the final command. If git remote -v is empty, create the remote repository first and add its URL as origin.
Finished project
Check the files before the next feature.
my-project/
├── adios.yaml
├── package.json
├── package-lock.json
└── src/
└── app/
├── api/
│ └── health/
│ └── route.ts
├── page.tsx
├── robots.ts
└── sitemap.tsCommon problems
Why does the Next.js app need a health route?
Adios uses the health route to confirm that the production process is ready before it promotes the release. Keep the response fast and return a successful status only when the app can serve traffic.
Why do I need to replace the site URL after the first deploy?
A sitemap needs absolute production URLs. The first Adios deployment creates the generated hostname, so replace the placeholder in adios.yaml with that hostname and deploy once more before treating the sitemap as final.
What if npm run build fails?
Fix the local production build before deploying. Start with the first error, confirm the Node version and lockfile, and do not use a successful development server as proof that the production build works.
What if the release starts but never becomes healthy?
Confirm package.json has a start script that runs next start, the app listens on port 3000, and adios.yaml uses the same port and /api/health path. Then inspect the runtime logs for the first startup or health-check error before deploying again.
What if the project does not have a Git remote?
Create an empty repository with your Git provider, add it as origin, confirm the branch name, and then push. Do not run the example push command until git remote -v shows the destination you expect.
Keep building
Use the same contract with an AI coding agent.
The AI guide turns these exact files and checks into prompts for Codex, ChatGPT, Gemini, and Claude.
Open the AI workflow