Images for Next.js apps from generated Dockerfiles using fly launch
will be dramatically smaller (read: ~400MB smaller) when using the standalone
output option in your next.config.js
Read the full documentation here: Run a Next.js App · Fly Docs
For new Next.js apps:
Ensure that your next.config.js
file contains output: "standalone"
/** @type {import('next').NextConfig} */
const nextConfig = {
output: "standalone"
};
export default nextConfig;
Then run fly launch
, and the appropriate Dockerfile will be generated.
For existing Next.js apps deployed to Fly.io:
Inside your Dockerfile, after running the build script (npm run build
), there should typically be a final COPY
instruction towards the end of one’s Dockerfile. Replace that with the following:
COPY --from=build /app/.next/standalone /app
COPY --from=build /app/.next/static /app/.next/static
COPY --from=build /app/public /app/public
Lastly, update your CMD
to the following:
CMD [ "node", "server.js" ]
3 Likes
Access Log Hack
If you are using the above with NextJS version 14.1, you can use the follow hack to create access logs:
- Add a file to your repository called
logging.js
that looks something like this:
/* eslint-disable no-console */
/**
* Log to console each request.
* @param { import('http').IncomingMessage } req
* @param { import('http').ServerResponse } res
*/
function log(req, res, requestTime) {
const user_agent = req.headers['user-agent'];
console.log(
JSON.stringify({
request_method: req.method,
request_uri: req.url,
request_time_ms: Number(requestTime.toFixed(1)),
content_type: req.headers.content_type,
user_agent,
status: res.statusCode,
reqId: req.headers['fly-request-id'],
x_forwarded_for: req.headers['x-forwarded-for'],
}),
);
}
module.exports = log;
- Add two commands to your Dockerfile, after the
COPY
of /app/public
something like:
COPY logging.js /app/logging.js
# Inject logging into next's server code
RUN sed -i -e '/"use strict";/a\const log = require("/app/logging")' \
-e '/await requestHandler(req, res)/s/^/ const startTime = performance.now()\n/' \
-e '/await requestHandler(req, res)/a\ const requestTime = performance.now() - startTime\n log(req,res,requestTime)\n' \
/app/node_modules/next/dist/server/lib/start-server.js
And you will have access logs with request times!