@andre.bonna/serverless-nextjs
    TypeScript icon, indicating that this package has built-in type declarations

    1.8.15 • Public • Published

    Serverless Nextjs Component

    logo

    A zero configuration Nextjs 9.0 serverless component with full feature parity.

    serverless Build Status Financial Contributors on Open Collective npm version Codacy Badge Coverage Status

    Contents

    Motivation

    Since Nextjs 8.0, serverless mode was introduced which provides a new low level API which projects like this can use to deploy onto different cloud providers. This project is a better version of the serverless plugin which focuses on addressing core issues like next 9 support, better development experience, the 200 CloudFormation resource limit and performance.

    Design principles

    1. Zero configuration by default

    There is no configuration needed. You can extend defaults based on your application needs.

    1. Feature parity with nextjs

    Users of this component should be able to use nextjs development tooling, aka next dev. It is the component's job to deploy your application ensuring parity with all of next's features we know and love.

    1. Fast deployments / no CloudFormation resource limits.

    With a simplified architecture and no use of CloudFormation, there are no limits to how many pages you can have in your application, plus deployment times are very fast! with the exception of CloudFront propagation times of course.

    Features

    Getting started

    Add your next application to the serverless.yml:

    # serverless.yml
     
    myNextApplication:
      component: serverless-next.js@{version_here} # it is recommended you pin the latest stable version of serverless-next.js

    Set your AWS credentials as environment variables:

    AWS_ACCESS_KEY_ID=accesskey
    AWS_SECRET_ACCESS_KEY=sshhh

    And simply deploy:

    $ serverless

    Custom domain name

    In most cases you wouldn't want to use CloudFront's distribution domain to access your application. Instead, you can specify a custom domain name.

    You can use any domain name but you must be using AWS Route53 for your DNS hosting. To migrate DNS records from an existing domain follow the instructions here. The requirements to use a custom domain name:

    • Route53 must include a hosted zone for your domain (e.g. mydomain.com) with a set of nameservers.
    • You must update the nameservers listed with your domain name registrar (e.g. namecheap, godaddy, etc.) with those provided for your new hosted zone.

    The serverless next.js component will automatically generate an SSL certificate and create a new record to point to your CloudFront distribution.

    # serverless.yml
     
    myNextApplication:
      component: serverless-next.js
      inputs:
        domain: "example.com" # sub-domain defaults to www

    You can also configure a subdomain:

    # serverless.yml
     
    myNextApplication:
      component: serverless-next.js
      inputs:
        domain: ["sub", "example.com"] # [ sub-domain, domain ]

    Custom CloudFront configuration

    To specify your own CloudFront inputs, just add any aws-cloudfront inputs under cloudfront:

    # serverless.yml
     
    myNextApplication:
      component: serverless-next.js
      inputs:
        cloudfront:
          # this is the default cache behaviour of the cloudfront distribution
          # the origin-request edge lambda associated to this cache behaviour does the pages server side rendering
          defaults:
            forward:
              headers:
                [
                  CloudFront-Is-Desktop-Viewer,
                  CloudFront-Is-Mobile-Viewer,
                  CloudFront-Is-Tablet-Viewer,
                ]
          # this is the cache behaviour for next.js api pages
          api:
            ttl: 10
          # you can set other cache behaviours like "defaults" above that can handle server side rendering
          # but more specific for a subset of your next.js pages
          /blog/*:
            ttl: 1000
            forward:
              cookies: "all"
              queryString: false
          /about:
            ttl: 3000
          # you can add custom origins to the cloudfront distribution
          origins:
            - url: /static
              pathPatterns:
                /wp-content/*:
                  ttl: 10
            - url: https://old-static.com
              pathPatterns:
                /old-static/*:
                  ttl: 10

    This is particularly useful for caching any of your next.js pages at CloudFront's edge locations. See this for an example application with custom cache configuration.

    Public directory caching

    By default, common image formats(gif|jpe?g|jp2|tiff|png|webp|bmp|svg|ico) under /public or /static folders have a one-year Cache-Control policy applied(public, max-age=31536000, must-revalidate). You may customize either the Cache-Control header value and the regex of which files to test, with publicDirectoryCache:

    myNextApplication:
      component: serverless-next.js
      inputs:
        publicDirectoryCache:
          value: public, max-age=604800
          test: /\.(gif|jpe?g|png|txt|xml)$/i

    value must be a valid Cache-Control policy and test must be a valid regex of the types of files you wish to test. If you don't want browsers to cache assets from the public directory, you can disable this:

    myNextApplication:
      component: serverless-next.js
      inputs:
        publicDirectoryCache: false

    AWS Permissions

    By default the Lambda@Edge functions run using AWSLambdaBasicExecutionRole which only allows uploading logs to CloudWatch. If you need permissions beyond this, like for example access to DynamoDB or any other AWS resource you will need your own custom policy arn:

    # serverless.yml
     
    myNextApplication:
      component: serverless-next.js
      inputs:
        policy: "arn:aws:iam::123456789012:policy/MyCustomPolicy"

    Make sure you add CloudWatch log permissions to your custom policy.

    Lambda At Edge Configuration

    Both default and api edge lambdas will be assigned 512mb of memory by default. This value can be altered by assigning a number to the memory input

    # serverless.yml
     
    myNextApplication:
      component: serverless-next.js
      inputs:
        memory: 1024

    Values for default and api lambdas can be separately defined by assigning memory to an object like so:

    # serverless.yml
     
    myNextApplication:
      component: serverless-next.js
      inputs:
        memory:
          defaultLambda: 1024
          apiLambda: 2048

    The same pattern can be followed for specifying the Node.js runtime (nodejs12.x by default):

    # serverless.yml
     
    myNextApplication:
      component: serverless-next.js
      inputs:
        runtime:
          defaultLambda: "nodejs10.x"
          apiLambda: "nodejs10.x"

    Similarly, the timeout by default is 10 seconds. To customise you can:

    # serverless.yml
     
    myNextApplication:
      component: serverless-next.js
      inputs:
        timeout:
          defaultLambda: 20
          apiLambda: 15

    Note the maximum timeout allowed for Lambda@Edge is 30 seconds. See https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-requirements-limits.html

    You can also set a custom name for default and api lambdas - if not the default is set by the aws-lambda serverless component to the resource id:

    # serverless.yml
     
    myNextApplication:
      component: serverless-next.js
      inputs:
        name:
          defaultLambda: fooDefaultLambda
          apiLambda: fooApiLambda

    Architecture

    architecture

    Four Cache Behaviours are created in CloudFront.

    The first two _next/* and static/* forward the requests to S3.

    The third is associated to a lambda function which is responsible for handling three types of requests.

    1. Server side rendered page. Any page that defines getInitialProps method will be rendered at this level and the response is returned immediately to the user.

    2. Statically optimised page. Requests to pages that were pre-compiled by next to HTML are forwarded to S3.

    3. Public resources. Requests to root level resources like /robots.txt, /favicon.ico, /manifest.json, etc. These are forwarded to S3.

    The reason why 2. and 3. have to go through Lambda@Edge first is because the routes don't conform to a pattern like _next/* or static/*. Also, one cache behaviour per route is a bad idea because CloudFront only allows 25 per distribution.

    The fourth cache behaviour handles next API requests api/*.

    Inputs

    Name Type Default Value Description
    domain Array null For example ['admin', 'portal.com']
    bucketName string null Custom bucket name where static assets are stored. By default is autogenerated.
    nextConfigDir string ./ Directory where your application next.config.js file is. This input is useful when the serverless.yml is not in the same directory as the next app.
    Note: nextConfigDir should be set if next.config.js distDir is used
    nextStaticDir string ./ If your static or public directory is not a direct child of nextConfigDir this is needed
    runtime string\|object nodejs12.x When assigned a value, both the default and api lambdas will be assigned the runtime defined in the value. When assigned to an object, values for the default and api lambdas can be separately defined
    memory number\|object 512 When assigned a number, both the default and api lambdas will be assigned memory of that value. When assigned to an object, values for the default and api lambdas can be separately defined
    timeout number\|object 10 Same as above
    name string\|object / When assigned a string, both the default and api lambdas will assigned name of that value. When assigned to an object, values for the default and api lambdas can be separately defined
    build boolean\|object true When true builds and deploys app, when false assume the app has been built and uses the .next .serverless_nextjs directories in nextConfigDir to deploy. If an object is passed build allows for overriding what script gets called and with what arguments.
    build.cmd string node_modules/.bin/next Build command
    build.args Array\|string ['build'] Arguments to pass to the build
    build.cwd string ./ Override the current working directory
    build.enabled boolean true Same as passing build:false but from within the config
    build.env object {} Add additional environment variables to the script
    cloudfront object {} Inputs to be passed to aws-cloudfront
    publicDirectoryCache boolean\|object true Customize the public/static folder asset caching policy. Assigning an object with value and/or test lets you customize the caching policy and the types of files being cached. Assigning false disables caching
    useServerlessTraceTarget boolean false Use the experimental-serverless-trace target to build your next app. This is the same build target that Vercel Now uses. See this RFC for details.

    Custom inputs can be configured like this:

    myNextApp:
      component: serverless-next.js
      inputs:
        bucketName: my-bucket

    FAQ

    My component doesn't deploy

    Make sure your serverless.yml uses the serverless-components format. serverless components differ from the original serverless framework, even though they are both accessible via the same CLI.

    Do

    # serverless.yml
    myNextApp:
      component: serverless-next.js
     
    myTable:
      component: serverless/aws-dynamodb
      inputs:
        name: Customers
    # other components

    Don't

    # serverless.yml
    provider:
      name: aws
      runtime: nodejs10.x
      region: eu-west-1
     
    myNextApp:
      component: serverless-next.js
     
    Resources: ...

    Note how the correct yaml doesn't declare a provider, Resources, etc.

    For deploying, don't run serverless deploy. Simply run serverless and that deploys your components declared in the serverless.yml file.

    For more information about serverless components go here.

    Should I use the serverless-plugin or this component?

    Users are encouraged to use this component instead of the serverless-plugin. This component was built and designed using lessons learned from the serverless plugin.

    How do I interact with other AWS Services within my app?

    See examples/dynamodb-crud for an example Todo application that interacts with DynamoDB.

    [CI/CD] A new CloudFront distribution is created on every CI build. I wasn't expecting that

    You need to commit your application state in source control. That is the files under the .serverless directory. The serverless team is currently working on remote state storage so this won't be necessary in the future.

    My lambda is deployed to us-east-1. How can I deploy it to another region?

    Serverless next.js is regionless. By design, serverless-next.js applications will be deployed across the globe to every CloudFront edge location. The lambda might look like is only deployed to us-east-1 but behind the scenes, it is replicated to every other region.

    I require passing additional information into my build

    See the sample below for an advanced build setup that includes passing additional arguments and environment variables to the build.

    # serverless.yml
    myDatabase:
      component: MY_DATABASE_COMPNENT
    myNextApp:
      component: serverless-next.js
      build:
        args: ["build", "custom/path/to/pages"]
        env:
          DATABASE_URL: ${myDatabase.databaseUrl}

    Contributing

    Please see the contributing guide.

    Contributors

    Code Contributors

    This project exists thanks to all the people who contribute. [Contribute].

    Financial Contributors

    Become a financial contributor and help us sustain our community. [Contribute]

    Individuals

    Organizations

    Support this project with your organization. Your logo will show up here with a link to your website. [Contribute]

    Install

    npm i @andre.bonna/serverless-nextjs

    DownloadsWeekly Downloads

    17

    Version

    1.8.15

    License

    MIT

    Unpacked Size

    3.41 MB

    Total Files

    291

    Last publish

    Collaborators

    • andre.bonna