vercel / next.js

The React Framework
https://nextjs.org
MIT License
127.47k stars 27.04k forks source link

Deployment to AWS Lambda #1406

Closed orenyomtov closed 7 years ago

orenyomtov commented 7 years ago

Is it possible to deploy a next.js web app to AWS Lambda & API Gateway? (using claudia for example)

arunoda commented 7 years ago

@orenyomtov That's doable. This is just a normal node app.

First build you app with next build (You could do this locally) Then push your app to lambda. Then run the app with npm start.

arunoda commented 7 years ago

Check this too: https://github.com/zeit/next.js#production-deployment

orenyomtov commented 7 years ago

Thanks @arunoda.

The issue which I do not know how to solve is routing the HTTP requests to next.js, because Lambda (+API Gateway) isn't a regular hosted node app listening to port 80.

For example, in order to run Express node apps on Lambda, the following library has been created: https://github.com/awslabs/aws-serverless-express

arunoda commented 7 years ago

You can use express with Next.js. See

It uses our Custom Server API

orenyomtov commented 7 years ago

@arunoda wow super interesting! This might be the way to go about it, thanks a lot.

Edit - it's working on AWS Lambda!

geovanisouza92 commented 7 years ago

@orenyomtov Could you share how you achieved this?

keeth commented 7 years ago

@geovanisouza92 I got it working using claudiajs and something like the following..

lambda.js

process.env.IN_LAMBDA = "1";
process.env.NODE_ENV = "production";
const awsServerlessExpress = require('aws-serverless-express');
const app = require('./server');
const server = awsServerlessExpress.createServer(app);
exports.handler = (event, context) => awsServerlessExpress.proxy(server, event, context);

server.js

const express = require('express');
const next = require('next');

const dev = process.env.NODE_ENV !== 'production';
const port = parseInt(process.env.PORT, 10) || 3000;
const app = next({ dev });
const handle = app.getRequestHandler();

function createServer() {
  const server = express();
  // add middleware, custom routing, whatever
  server.get('*', (req, res) => handle(req, res));
  return server;
}

if (process.env.IN_LAMBDA) {
  module.exports = createServer();
} else {
  app.prepare().then(() => {
    const server = createServer();
    server.listen(port);
  });
}

basically I skip doing prepare() in lambda.

make sure you 'npm run build' before you deploy.

not sure if this is optimal but it seems to be working.

the app/server naming is confusing, but i've just gone with default names from the examples of each project

maziarz commented 7 years ago

This sounds awesome! Would be cool to turn it into a deployment tutorial :-)

alexandregiordanelli commented 7 years ago

@keeth @arunoda There are any problem in to that? skip app.prepare? The documentation doesnt say a lot about this method.. is this method (app.prepare()) necessary only on dev?

kylealwyn commented 6 years ago

looks like app.prepare() just starts the hot reloader if in dev mode: https://github.com/zeit/next.js/blob/337fb6a9aadb61c916f0121c899e463819cd3f33/server/index.js#L110-L114

Vadorequest commented 6 years ago

I'm working on a detailed tutorial at https://github.com/Vadorequest/serverless-with-next

Currently stuck because of some Serverless/webpack issue once deployed to AWS, but for anyone interested to take a look, the development environment works fine.

Feedback greatly appreciated!

faizhasim commented 6 years ago

I wonder whether this will work with serverless-http? After all, serverless-http provides a layer of shim between lambda and express/koa api. Running things in the same process would be easier to debug, compared to spawning new process to run dedicated express app.

mitchellhuang commented 6 years ago

I believe @keeth's example won't work after Next 5. You'll need to do app.prepare() in the lambda handler as well.

const serverless = require('serverless-http');
exports.handler = (event, context, callback) => {
  app.prepare()
  .then(() => {
    const handler = serverless(server, {
      binary: binaryMimeTypes
    });
    return handler(event, context, callback)
  })
}
mununki commented 5 years ago

Here I'd like to share my research about deploying Next.js app on Lambda. I'm using apex up for it because it makes me not to change my code much. I hope this can be a small tip for later coming researchers.

https://github.com/mattdamon108/nextjs-with-lambda

danielcondemarin commented 5 years ago

For folks using the serverless framework, I've been working on a plugin that targets next 8 serverless. It adds a compat layer between the AWS Lambdas and Next pages as they have different handler signatures and deploys one Lambda function per Next page. Feedback would be great 👍

petrbela commented 5 years ago

@danielcondemarin's package is great, however, it creates a lambda function for every path (currently), which might not be the best solution for everyone.

If you're using a single server on lambda (through serverless-http), I found that executing app.prepare() (which recompiles source files into .next) in the lambda is not the best option. I'd recommend running NODE_ENV=production next build as part of your deployment process, and then serverless can just deploy the .next folder. This will also make it work with serverless-offline (which by default rebuilds the handler on every request).