Run a NextJS App
Getting an application running on Fly.io is essentially working out how to package it as a deployable image. Once packaged it can be deployed to the Fly.io global application platform.
In this guide we’ll learn how to deploy a NextJS application on Fly.io.
You can deploy your NextJS app on Fly with minimal effort, our CLI will do the heavy lifting. You can use your existing NextJS app or you can create one using the tutorial then come back here to deploy your app.
Generate the NextJS app
If you just want to see how Fly deployment works, follow these steps.
First, install flyctl, your Fly.io app command center, and sign up to Fly.io if you haven’t already.
Now let’s launch your NextJS app.
cd nextjs-blog
fly launch
Creating app in /Users/me/nextjs-blog
Scanning source code
Detected a Next.js app
? Choose an app name (leave blank to generate one): nextjs-blog
? Select Organization: flyio (flyio)
Some regions require a paid plan (bom, fra, maa).
See https://fly.io/plans to set up a plan.
? Choose a region for deployment: Ashburn, Virginia (US) (iad)
App will use 'iad' region as primary
Created app 'nextjs-blog' in organization 'personal'
Admin URL: https://fly.io/apps/nextjs-blog
Hostname: nextjs-blog.fly.dev
create Dockerfile
Wrote config file fly.toml
Validating /Users/rubys/tmp/nextjs-blog/fly.toml
Platform: machines
✓ Configuration is valid
If you need custom packages installed, or have problems with your deployment
build, you may need to edit the Dockerfile for app-specific changes. If you
need help, please post on https://community.fly.io.
Now: run 'fly deploy' to deploy your Next.js app.
That’s it! Run fly apps open
to see your deployed app in action.
Try a few other commands:
fly logs
- Tail your application logsfly status
- View your app’s current deployment statusfly ssh console
- Open a terminal on your VMfly deploy
- Deploy the application after making changes
Connecting to databases
Unlike some other frameworks, Next.js does not bundle a database adapter, instead you are free to chose the ORM or node module you wish.
Fly.io will provide a DATABASE_URL
that you can use at runtime to
connect to your database. How you will use this will depend on the
database module you chose. Prisma is
a popular choice, and connecting to your database using prisma is done
through your `prisma/schema.prisma’ file. An example:
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
If you are unsure how to connect using your favorite adaptor, check out our Vanilla with Candy Sprinkles blog entry and select the configuration that most closely matches your application and see how it works. If you still have questions, post the on our community forum.
Static site generation with Databases
By default, the build machine does not have access to your production
database. This means you won’t be able to access your database from
inside methods like getStaticProps
.
Should this be something your application requires, there are two approaches for addressing this: build time secrets and deferring the generation to deploy.
Build time secrets
This approach won’t work for SQLite3 as the build machine still won’t have access to your volume, but can be used with PostgreSQL, MySQL and other such databases.
First you need to obtain the secrets you will need to deploy. Often this
is only the value of DATABASE_URL
. If you don’t know the value of this
secret, fly console
and printenv DATABASE_URL
can obtain this value
for you.
Next you need to modify your Dockerfile to mount a secret. You can follow the instructions for Mounting secrets or you can let the dockerfile generator make the changes for you:
npx dockerfile --mount-secret=DATABASE_URL
Finally you need to pass the secret on each deploy:
fly deploy --build-secret DATABASE_URL=value
Replace value above with the actual secret.
It might be worth putting this command into a shell script or batch file.
Deferring static site generation
An alternate approach, one that works with sqlite3 too, is to defer the running of the build step to just after before your web server is started. The upside is that your build has full access to all of your deployment secrets.
This involves replacing your entrypoint in your Dockerfile with a script,
and having that script run npm build
(or equivalent) prior to starting
your server. You can let the dockerfile generator take care of these
changes for you:
npx dockerfile --build=defer
Downsides of this approach:
- Your deployment machines will need enough memory to run a build. See:
fly scale memory
andswap_size_mb
for two options. - You may need to adjust the grace_period for any http service checks.
- If you are only running one machine there will be a period of time where your server is inaccessible while the site is being statically generated.
- If you run multiple machines, the statis site generation will be run on each increasing the total time before any changes are fully deployed.
Disabling telemetry in production
During server startup the following messages may appear in your log:
Attention: Next.js now collects completely anonymous telemetry regarding usage.
This information is used to shape Next.js' roadmap and prioritize features.
You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:
https://nextjs.org/telemetry
The following command can be used to modify your Dockerfile to disable telemetry:
npx dockerfile --env-base=NEXT_TELEMETRY_DISABLED:1
Out of memory: Killed process
If you should happen to see lines like the following in your logs:
Out of memory: Killed process
Two links that may be of help:
Fetch failure when optimizing images
If your application uses the <Image>
element and your images aren’t showing and you are seeing the following in your logs:
TypeError: fetch failed
Scan backwards in your logs for the following:
Warning: For production Image Optimization with Next.js, the optional 'sharp' package is strongly recommended. Run 'npm i sharp', and Next.js will use it automatically for Image Optimization.
Read more: https://nextjs.org/docs/messages/sharp-missing-in-production
Follow the instructions in the message, and then redeploy:
npm i sharp
fly deploy
What about build time environment variables?
If you’re an NextJS user you might know that it supports exposing environment variables to the browser using variables with name starting with NEXT_PUBLIC_
.
For our build system to understand that you need to tweak two sections we generate for you, fly.toml
and our Dockerfile
.
Search for [build.args]
on your fly.toml
and add the variables you need there.
[build.args]
NEXT_PUBLIC_EXAMPLE="This is the value"
NEXT_PUBLIC_OTHER="Other value"
Then go to your Dockerfile
and add ARG
instructions before your FROM base as build
line like this:
# Throw-away build stage to reduce size of final image
FROM base as build
# Build arguments
ARG NEXT_PUBLIC_EXAMPLE="value"
ARG NEXT_PUBLIC_OTHER="Other value"
The dockerfile-node application can be used to help with this. Update your dockerfile using the following command:
npx dockerfile "--arg-build=NEXT_PUBLIC_EXAMPLE:value" \
"--arg-build=NEXT_PUBLIC_OTHER=Other value"