NavigationContentFooter
Jump toSuggest an edit

Deploy a Next.js application using Scaleway Serverless Containers and Serverless SQL Databases

Reviewed on 16 September 2024Published on 14 March 2024
  • nextjs
  • sql

This tutorial will guide you through deploying a fully serverless Next.js application using a Serverless Container and a Serverless SQL Database.

You can either deploy your application:

  • step by step using Scaleway CLI to understand each detailed action performed, and the resources and subresources required
  • using a Terraform template to deploy your application faster and have a ready-to-use Infrastructure as Code.

Before you start

To complete the actions presented below, you must have:

  • A Scaleway account logged into the console
  • Owner status or IAM permissions allowing you to perform actions in the intended Organization
  • A valid API key
  • Installed and initialized the Scaleway CLI
  • Installed Docker Engine
  • Installed Node 18 or newer

Deploy Next.js application frontend using Serverless Containers

Initializing the project

  1. Run the command below in a terminal to export your API access and secret keys as environment variables:

    export SCW_ACCESS_KEY=$(scw config get access-key)
    export SCW_SECRET_KEY=$(scw config get secret-key)
  2. Run the command below to make sure the environment variables are properly set:

    scw info

    This command displays your access key and secret key in the last two lines of the output. The ORIGIN column should display env (SCW_ACCESS_KEY) and env (SCW_SECRET_KEY), and not default profile.

    KEY VALUE ORIGIN
    (...)
    access_key SCWF9DETBF829TAFB1TB env (SCW_ACCESS_KEY)
    secret_key 9a1bcf92-xxxx-xxxx-xxxx-xxxxxxxxxxxx env (SCW_SECRET_KEY)
  3. Access the folder where you want to store your project repository and run the following command to initialize a blog template application:

    npx create-next-app --example blog-starter my-nextjs-blog
  4. Type y when prompted to install the dependencies:

    Need to install the following packages:
    create-next-app@14.0.3
    Ok to proceed? (y) y

    This will create a folder named my-nextjs-blog.

  5. Access the folder you just created:

    cd my-nextjs-blog
  6. Make sure you can run the application locally:

    npm run dev
  7. Access http://localhost:3000 in a browser. The blog template displays.

Creating an image containing your Next.js app

  1. Run the following command to create a Dockerfile:

    touch Dockerfile
  2. Add the following code to it:

    # syntax=docker/dockerfile:1
    FROM node:20-alpine
    #Built time arguments used for pre-rendering
    ARG PGHOST
    ARG PGPORT
    ARG PGDATABASE
    ARG PGUSER
    ARG PGPASSWORD
    WORKDIR /usr/app
    COPY ./ ./
    RUN npm install
    RUN npm run build
    #Web application configuration
    ENV PORT=8080
    #Database configuration used for dynamically rendered data. These default values should be overwritten by container runtime environment variables
    ENV PGHOST=localhost
    ENV PGPORT=5432
    ENV PGDATABASE=database
    ENV PGUSER=user
    ENV PGPASSWORD=password
    CMD npm run start
  3. Create a .dockerignore file by copying the .gitignore file:

    cp .gitignore .dockerignore

    Docker will now ignore node dependencies and build files generated during the container build.

  4. Build your application container:

    docker build -t my-nextjs-blog .
  5. Check that your container runs locally:

    docker run -it -p 8080:8080 my-nextjs-blog
  6. Access http://localhost:8080 in a browser. The blog template displays.

    Tip

    When connecting to the webpage, your terminal running Docker might display the following error Error: ENOENT: no such file or directory, open '/usr/app/_posts/%5Bslug%5D.md'. This will be fixed in further steps.

Pushing the image to Scaleway Container Registry

  1. Run the following command to create a Container Registry namespace and export its endpoint as a variable:

    export REGISTRY_ENDPOINT=$(scw registry namespace create -o json | jq -r '.endpoint')
  2. Log in to your Container Registry from your local terminal:

    docker login $REGISTRY_ENDPOINT -u nologin --password-stdin <<< "$SCW_SECRET_KEY"

    The following output displays:

    Login Succeeded
  3. Tag and push your container image to your Container Registry namespace:

    docker tag my-nextjs-blog:latest $REGISTRY_ENDPOINT/my-nextjs-blog:latest
    docker push $REGISTRY_ENDPOINT/my-nextjs-blog:latest

Deploying the container with Scaleway Serverless Containers

  1. Run the following command to create a Serverless Containers namespace and export its ID as a variable:

    export CONTAINER_NAMESPACE_ID=$(scw container namespace create name="my-nextjs-blog-ns" -o json | jq -r '.id')
  2. Deploy a Serverless Container with your application image:

    scw container container create name="my-nextjs-blog" namespace-id=$CONTAINER_NAMESPACE_ID registry-image=$REGISTRY_ENDPOINT/my-nextjs-blog:latest
    Tip

    The first deployment can take up to two minutes. You can check the deployment status with the following command:

    scw container container list name=my-nextjs-blog

    When the status appears as ready, you can access the website via your browser.

  3. Copy the endpoint URL displayed next to the DomainName property, and paste it into your browser. The blog template displays.

Your Next.js application frontend is now online.

Your application cannot store any data persistently yet. We will now add a serverless storage in the next section.

Add serverless storage to your application using a Serverless SQL Database

Setting up the database

  1. Run the following command to create a Serverless SQL Database and export its attributes as variables:

    export PGHOST=$(scw sdb-sql database create name=tutorial-nextjs-blog-db cpu-min=0 cpu-max=4 -o json | jq -r '.endpoint' | cut -d "/" -f3 | cut -d ":" -f1 )
    export PGPORT='5432'
    export PGDATABASE='tutorial-nextjs-blog-db'
    export PGUSER=$(scw iam api-key get $SCW_ACCESS_KEY -o json | jq -r '.user_id')
    export PGPASSWORD=$SCW_SECRET_KEY

    These environment variables are default PostgreSQL variables and are automatically recognized by most PostgreSQL-compatible tools.

  2. Connect to your database using the psql tool:

    psql
    Note

    psql automatically uses PGHOST, PGPORT, PGDATABASE, PGUSER, PGPASSWORD environment variables as default arguments.

    An input field with the name of your database displays:

    psql (15.3, server 16.1 (Debian 16.1-1.pgdg120+1))
    SSL connection (protocol: TLSv1.3, cipher: TLS_AES_128_GCM_SHA256, compression: off)
    Type "help" for help.
    tutorial-nextjs=>
  3. Create a table structure with the following query:

    create table posts (title char(100), excerpt text, coverImage text, date date, author_name char(50), author_picture text, ogImage_url text, slug char(50), content text);
  4. Add data using the following command:

    insert into posts values
    ('Learn How to Pre-render Pages Using Static Generation with Next.js',
    'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus.',
    '/assets/blog/hello-world/cover.jpg',
    '2020-03-16T05:35:07.322Z',
    'Tim Neutkens',
    '/assets/blog/authors/tim.jpeg',
    '/assets/blog/hello-world/cover.jpg',
    'hello-world',
    'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus. Praesent elementum facilisis leo vel fringilla. Congue mauris rhoncus aenean vel. Egestas sed tempus urna et pharetra pharetra massa massa ultricies.'),
    ('Dynamic Routing and Static Generation',
    'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus.',
    '/assets/blog/dynamic-routing/cover.jpg',
    '2020-03-16T05:35:07.322Z',
    'JJ Kasper',
    '/assets/blog/authors/jj.jpeg',
    '/assets/blog/dynamic-routing/cover.jpg',
    'dynamic-routing',
    'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus. Praesent elementum facilisis leo vel fringilla. Congue mauris rhoncus aenean vel. Egestas sed tempus urna et pharetra pharetra massa massa ultricies.'),
    ('Preview Mode for Static Generation',
    'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus.',
    '/assets/blog/preview/cover.jpg',
    '2020-03-16T05:35:07.322Z',
    'Joe Haddad',
    '/assets/blog/authors/joe.jpeg',
    '/assets/blog/preview/cover.jpg',
    'preview',
    'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus. Praesent elementum facilisis leo vel fringilla. Congue mauris rhoncus aenean vel. Egestas sed tempus urna et pharetra pharetra massa massa ultricies.');
  5. Exit the database query interface with the following command:

    exit
  6. Run the command below to add the node-postgres dependency to your application:

    npm install pg && npm install --save-dev @types/pg

    This library is required to connect from your front end to your database.

Your application folder should be called my-nextjs-blog and structured as follows:

my-nextjs-blog/
.next/
app/
node_modules/
public/
pages/
src/
package.json
tsconfig.json

Integrating the database into your application

You need to edit 3 files to have a proper integration with your database.

Tip

If you want to avoid doing these modifications manually, you can also retrieve the final code from this tutorial from our serverless-examples repository with the command below:

git clone git@github.com:scaleway/serverless-examples.git

Note that this repository differs slightly in configuration, as it will dynamically render pages and not pre-render them in the Nextjs app build phase.

  1. Edit the file located at src/lib/api.ts by replacing its content with the following code. This will switch frontend content from local data to your Serverless SQL Database.

    import { Post } from "@/interfaces/post";
    import fs from "fs";
    import matter from "gray-matter";
    import { join } from "path";
    import { Client } from 'pg'
    export type Row = {
    slug: string;
    title: string;
    date: Date;
    coverimage: string;
    author_name: string;
    author_picture: string;
    excerpt: string;
    ogimage_url: string;
    content: string;
    preview?: boolean;
    };
    const client = new Client({
    ssl: {
    rejectUnauthorized: false,
    }
    })
    const connect = async () => {
    await client.connect()
    }
    connect()
    //This default function handles Nextjs pre-rendering with undefined values
    export function getPostFromRow(row: Row){
    if (row === undefined){
    var postRow: Row = {
    slug: "Title",
    title: "Excerpt",
    date: new Date("2024-01-16"),
    coverimage: "",
    author_name: "",
    author_picture: "",
    excerpt: "",
    ogimage_url: "",
    content: "",
    preview: false
    }
    } else{
    var postRow = row
    }
    const post = {
    title: postRow.title,
    excerpt: postRow.excerpt,
    coverImage: postRow.coverimage,
    date: postRow.date.toISOString(),
    author: {
    name: postRow.author_name,
    picture: postRow.author_picture
    },
    ogImage: {
    url: postRow.ogimage_url
    },
    slug: postRow.slug,
    content: postRow.content,
    preview: false
    }
    return post;
    }
    export async function getPostBySlug(slug: string): Promise<Post> {
    const data = await client.query('SELECT * FROM posts WHERE slug=$1;',[slug])
    const post = getPostFromRow(data.rows[0])
    return post;
    }
    export async function getAllPosts(): Promise<Post[]> {
    const data = await client.query('SELECT * FROM posts;')
    const posts = data.rows.map((row) => (getPostFromRow(row)))
    return posts;
    }
  2. Edit the file located at src/app/page.tsx by replacing its content with the following code. This will update the main application home page which displays the posts list.

    import Container from "@/app/_components/container";
    import { HeroPost } from "@/app/_components/hero-post";
    import { Intro } from "@/app/_components/intro";
    import { MoreStories } from "@/app/_components/more-stories";
    import { getAllPosts } from "../lib/api";
    export default async function Index() {
    const allPosts = await getAllPosts();
    const heroPost = allPosts[0];
    const morePosts = allPosts.slice(1);
    return (
    <main>
    <Container>
    <Intro />
    <HeroPost
    title={heroPost.title}
    coverImage={heroPost.coverImage}
    date={heroPost.date}
    author={heroPost.author}
    slug={heroPost.slug}
    excerpt={heroPost.excerpt}
    />
    {morePosts.length > 0 && <MoreStories posts={morePosts} />}
    </Container>
    </main>
    );
    }
  3. Edit the file located at src/app/posts/[slug]/page.tsx by replacing its content with the following code. This will update pages that display a single post.

    import { Metadata } from "next";
    import { notFound } from "next/navigation";
    import { getAllPosts, getPostBySlug } from "../../../lib/api";
    import { CMS_NAME } from "../../../lib/constants";
    import markdownToHtml from "../../../lib/markdownToHtml";
    import Alert from "../../_components/alert";
    import Container from "../../_components/container";
    import Header from "../../_components/header";
    import { PostBody } from "../../_components/post-body";
    import { PostHeader } from "../../_components/post-header";
    export default async function Post({ params }: Params) {
    const post = await getPostBySlug(params.slug)
    if (!post) {
    return notFound();
    }
    return (
    <main>
    <Alert preview={post.preview} />
    <Container>
    <Header />
    <article className="mb-32">
    <PostHeader
    title={post.title}
    coverImage={post.coverImage}
    date={post.date}
    author={post.author}
    />
    <PostBody content={post.content} />
    </article>
    </Container>
    </main>
    );
    }
    type Params = {
    params: {
    slug: string;
    };
    };
    export async function generateMetadata({ params }: Params): Promise<Metadata> {
    const post = await getPostBySlug(params.slug);
    if (!post) {
    return notFound();
    }
    const title = `${post.title} | Next.js Blog Example with ${CMS_NAME}`;
    return {
    openGraph: {
    title,
    images: [post.ogImage.url],
    },
    };
    }
    export async function generateStaticParams() {
    const posts = await getAllPosts();
    return posts.map((post) => ({
    slug: post.slug,
    }));
    }
  4. Run the following command to ensure that you can run the application locally:

    npm run dev
  5. Access http://localhost:3000 in a browser. The images and titles of the first blog post have been updated with the content from your database.

Congratulations! You can already deploy your application by building a new container version, pushing it to the Container Registry, and deploying it to Serverless Containers.

However, your application would then connect with your user credentials, which is not a recommended security practice. To secure your deployment, we will now add a dedicated IAM application, give it the minimum required permissions, and provide its credentials to your application.

Secure and redeploy your application

  1. Run the following command to create an IAM application and export it as a variable:

    export SCW_APPLICATION_ID=$(scw iam application create name=tutorial-nextjs-app -o json | jq -r '.id')

    The SCW_APPLICATION_ID environment variable will store the IAM application ID so you can use it in later commands.

  2. Create an IAM policy giving your application rights to access the database:

    scw iam policy create application-id=$SCW_APPLICATION_ID name=tutorial-nextjs-policy rules.0.organization-id=$(scw config get default-organization-id) rules.0.permission-set-names.0=ServerlessSQLDatabaseFullAccess

    The permission ServerlessSQLDatabaseFullAccess lets your application read and write data or create new databases. You can restrict this later to fit your database use cases, using ServerlessSQLDatabaseRead or ServerlessSQLDatabaseReadWrite permissions sets.

  3. Create an IAM API Key and export its secret key as an environment variable:

    export SCW_APPLICATION_SECRET=$(scw iam api-key create application-id=$SCW_APPLICATION_ID -o json | jq -r '.secret_key')
  4. Build your application container with the updated code:

    docker build -t my-nextjs-blog --build-arg PGHOST --build-arg PGDATABASE --build-arg PGPORT --build-arg PGUSER=$SCW_APPLICATION_ID --build-arg PGPASSWORD=$SCW_APPLICATION_SECRET .

    This time, the build command requires environment variables, because Next.js pre-rendering will access your database while building time to load page content.

    You can check that your container is running correctly locally with:

    docker run -it -p 8080:8080 -e PGHOST -e PGDATABASE -e PGPORT -e PGUSER=$SCW_APPLICATION_ID -e PGPASSWORD=$SCW_APPLICATION_SECRET my-nextjs-blog
  5. Access http://localhost:8080 in a browser. The blog template displays.

  6. Push your containerized application to the Container Registry:

    docker tag my-nextjs-blog:latest $REGISTRY_ENDPOINT/my-nextjs-blog:latest
    docker push $REGISTRY_ENDPOINT/my-nextjs-blog:latest
  7. Retrieve your container’s ID:

    export CONTAINER_ID=$(scw container container list name="my-nextjs-blog" -o json | jq -r '.[0].id')
  8. Redeploy your Serverless Container:

    scw container container deploy $CONTAINER_ID
  9. Refresh your browser page displaying the blog. An updated version displays.

Congratulations, you have deployed a full serverless Next.js application!

Going further with containers

  • Edit the source code locally, apply scw container deploy again, and see the new version go live in seconds.

  • Inspect your newly created resources in the Scaleway console:

    • You can display your Registry namespace and container image in the Container Registry section.

    • You can display your Serverless Containers namespace and container deployment in the Serverless Containers section.

    • You can display your Serverless SQL Database in the Serverless SQL Databases section.

  • Fine-tune deployment options such as autoscaling, targeted regions, and more. You can find more information by typing scw container deploy --help in your terminal, or by referring to the dedicated documentation.

Deploy a Next.js application using Terraform templates

Note

You must have Terraform installed and configured with Scaleway Terraform Provider for this part.

Initialize the project

  1. Run the command below to export your access key and secret key as environment variables:

    export SCW_ACCESS_KEY=$(scw config get access-key)
    export SCW_SECRET_KEY=$(scw config get secret-key)
  2. Run the command below to make sure the environment variables are properly set:

    scw info

    This command displays your access_key and secret_key in the two last lines of the output. The ORIGIN column should display env (SCW_ACCESS_KEY) and env (SCW_SECRET_KEY), and not default profile.

    KEY VALUE ORIGIN
    (...)
    access_key SCWF9DETBF829TAFB1TB env (SCW_ACCESS_KEY)
    secret_key 9a1bcf92-xxxx-xxxx-xxxx-xxxxxxxxxxxx env (SCW_SECRET_KEY)
  3. Run the following command to create a folder to store the template source code, and access it:

    mkdir my-nextjs-blog
    && cd my-nextjs-blog
  4. Copy the files from the serverless-examples repository to the folder.

    Note

    These files extend the blog demo application from npx create-next-app --example blog-starter my-nextjs-blog, and add the required code to fetch data from a database instead of static markdown files.

  5. Install the required dependencies:

    npm install
  6. Confirm you can run the application locally with the following commands:

    npm run dev
  7. Access http://localhost:3000 in a browser. The blog template displays.

Building the image containing your Next.js app

  1. Build your application container with:

    docker build -t my-nextjs-blog .
    Tip

    An error message Error: connect ECONNREFUSED might display when building. This is linked to Next.js prerendering stage without any database to connect to yet but will raise any issue at runtime because all pages will be dynamically rendered.

  2. Run the following command to check that your container runs locally:

    docker run -it -p 8080:8080 my-nextjs-blog
  3. Go to localhots:8080 in your browser. The message below displays because your application is not connected to the database yet.

    Application error: a server-side exception has occurred (see the server logs for more information)

Pushing the image containing your Next.js app

  1. Run the following command to create a Container Registry namespace and export its endpoint as a variable:

    export REGISTRY_ENDPOINT=$(scw registry namespace create -o json | jq -r '.endpoint')
  2. Log in to your Container Registry from your local terminal:

    docker login $REGISTRY_ENDPOINT -u nologin --password-stdin <<< "$SCW_SECRET_KEY"

    The following output displays:

    Login Succeeded
  3. Tag and push your container image to your Container Registry namespace:

    docker tag my-nextjs-blog:latest $REGISTRY_ENDPOINT/my-nextjs-blog:latest
    docker push $REGISTRY_ENDPOINT/my-nextjs-blog:latest

Creating the Terraform configuration

  1. Run the following command to create a new folder inside my-nextjs-blog to store your Terraform files, and access it:

    cd ..
    mkdir terraform-nextjs-blog
    && cd terraform-nextjs-blog
  2. Create an empty main.tf Terraform file inside the folder.

    Your application folder should now be structured as follows:

    my-nextjs-blog/
    terraform-nextjs-blog/
    main.tf
  3. Add the following code to your main.tf file:

    terraform {
    required_providers {
    scaleway = {
    source = "scaleway/scaleway"
    }
    }
    required_version = ">= 0.13"
    }
    variable "REGISTRY_ENDPOINT" {
    type = string
    description = "Container Registry endpoint where your application container is stored"
    }
    variable "DEFAULT_PROJECT_ID" {
    type = string
    description = "Project id where your resources will be created"
    }
    resource scaleway_container_namespace main {
    name = "tutorial-nextjs-blog-tf"
    description = "Namespace created for full serverless Nextjs app deployment"
    }
    resource scaleway_container main {
    name = "tutorial-nextjs-blog-tf"
    description = "Container for Nextjs blog"
    namespace_id = scaleway_container_namespace.main.id
    registry_image = "${var.REGISTRY_ENDPOINT}/my-nextjs-blog:latest"
    port = 8080
    cpu_limit = 560
    memory_limit = 1024
    min_scale = 0
    max_scale = 5
    timeout = 600
    max_concurrency = 80
    privacy = "public"
    protocol = "http1"
    deploy = true
    environment_variables = {
    "PGUSER" = scaleway_iam_application.app.id,
    "PGHOST" = trimsuffix(trimprefix(regex(":\\/\\/.*:",scaleway_sdb_sql_database.database.endpoint), "://"),":")
    "PGDATABASE" = scaleway_sdb_sql_database.database.name,
    "PGPORT" = trimprefix(regex(":[0-9]{1,5}",scaleway_sdb_sql_database.database.endpoint), ":")
    }
    secret_environment_variables = {
    "PGPASSWORD" = scaleway_iam_api_key.api_key.secret_key,
    }
    }
    resource scaleway_iam_application "app" {
    name = "tutorial-nextjs-app-tf"
    }
    resource scaleway_iam_policy "db_access" {
    name = "tutorial-nextjs-policy-tf"
    description = "Gives tutorial Nextjs app access to Serverless SQL Database"
    application_id = scaleway_iam_application.app.id
    rule {
    project_ids = ["${var.DEFAULT_PROJECT_ID}"]
    permission_set_names = ["ServerlessSQLDatabaseReadWrite"]
    }
    }
    resource scaleway_iam_api_key "api_key" {
    application_id = scaleway_iam_application.app.id
    }
    resource scaleway_sdb_sql_database "database" {
    name = "tutorial-nextjs-tf"
    min_cpu = 0
    max_cpu = 8
    }
    output "database_connection_string" {
    // Output as an example, you can give this string to your application
    value = format("postgres://%s:%s@%s",
    scaleway_iam_application.app.id,
    scaleway_iam_api_key.api_key.secret_key,
    trimprefix(scaleway_sdb_sql_database.database.endpoint, "postgres://"),
    )
    sensitive = true
    }
    output "container_url" {
    // Output as an example, you can give this string to your application
    value = scaleway_container.main.domain_name
    sensitive = true
    }

The Terraform file creates several resources:

  • A Serverless Containers namespace, that contains a Serverless Container, which hosts your Next.js application

  • A Serverless SQL Database which stores posts data

  • An IAM policy which grants your application the right permissions

  • An IAM application, used as a principal for your IAM policy

  • An IAM API key used as credentials to authenticate your application to the database

Deploying the app with Terraform

  1. Run the following command to initialize the Terraform working directory:

    terraform init
  2. Add the REGISTRY_ENDPOINT and DEFAULT_PROJECT_ID environment variables to Terraform:

    export TF_VAR_REGISTRY_ENDPOINT=$REGISTRY_ENDPOINT
    export TF_VAR_DEFAULT_PROJECT_ID=$(scw config get default-project-id)
  3. Create and review the Terraform execution plan of your infrastructure:

    terraform plan
  4. Deploy your application by executing the actions listed in your Terraform plan:

    terraform apply

    The output will provide the URL with which you can access your application and the connection string for your database. Since they contain sensitive values, they are hidden by default.

  5. Run the following command to display them:

    terraform output -json

    A similar output displays:

    {
    "container_url": {
    "sensitive": true,
    "type": "string",
    "value": "tutorialnextjsblogtfaxtypxrf-tutorial-nextjs-blog-tf.functions.fnc.fr-par.scw.cloud"
    },
    "database_connection_string": {
    "sensitive": true,
    "type": "string",
    "value": "postgres://example-f6b7-40cc-9ae8-7f24e64c6531:example-c770-46ea-b785-94bf39536e6a@650c9680-1100-48e4-b5a6-ff2ff5bcf142.pg.sdb.fr-par.scw.cloud:5432/tutorial-nextjs-tf?sslmode=require"
    }
    }
  6. Copy the container URL from the output and paste it into a browser to access your application. However, no post will be displayed because your database is still empty.

Adding content to the Serverless SQL Database

  1. Run the following command to connect to your database using the link provided by Terraform’s output:

    psql $(terraform output -json | jq -r '.database_connection_string.value')

    An input field with the name of your database displays:

    psql (15.3, server 16.1 (Debian 16.1-1.pgdg120+1))
    SSL connection (protocol: TLSv1.3, cipher: TLS_AES_128_GCM_SHA256, compression: off)
    Type "help" for help.
    tutorial-nextjs=>
  2. Create a table structure with the following query:

    create table posts (title char(100), excerpt text, coverImage text, date date, author_name char(50), author_picture text, ogImage_url text, slug char(50), content text);
  3. Add data using the following command:

    insert into posts values
    ('Learn How to Pre-render Pages Using Static Generation with Next.js',
    'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus.',
    '/assets/blog/hello-world/cover.jpg',
    '2020-03-16T05:35:07.322Z',
    'Tim Neutkens',
    '/assets/blog/authors/tim.jpeg',
    '/assets/blog/hello-world/cover.jpg',
    'hello-world',
    'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus. Praesent elementum facilisis leo vel fringilla. Congue mauris rhoncus aenean vel. Egestas sed tempus urna et pharetra pharetra massa massa ultricies.'),
    ('Dynamic Routing and Static Generation',
    'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus.',
    '/assets/blog/dynamic-routing/cover.jpg',
    '2020-03-16T05:35:07.322Z',
    'JJ Kasper',
    '/assets/blog/authors/jj.jpeg',
    '/assets/blog/dynamic-routing/cover.jpg',
    'dynamic-routing',
    'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus. Praesent elementum facilisis leo vel fringilla. Congue mauris rhoncus aenean vel. Egestas sed tempus urna et pharetra pharetra massa massa ultricies.'),
    ('Preview Mode for Static Generation',
    'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus.',
    '/assets/blog/preview/cover.jpg',
    '2020-03-16T05:35:07.322Z',
    'Joe Haddad',
    '/assets/blog/authors/joe.jpeg',
    '/assets/blog/preview/cover.jpg',
    'preview',
    'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus. Praesent elementum facilisis leo vel fringilla. Congue mauris rhoncus aenean vel. Egestas sed tempus urna et pharetra pharetra massa massa ultricies.');
  4. Exit the database query interface with the following command:

    exit
  5. Run the command below again, and open the container URL in a browser to access your application.

    terraform output -json

    Your serverless application is now online.

  6. Once you are done, run the following command to stop all your resources:

    terraform destroy

Going further

  • Edit the source code locally, then:

    • Build a new container version with the following command:

      docker build -t my-nextjs-blog .
    • Push the new container to Container Registry:

      docker tag my-nextjs-blog:latest $REGISTRY_ENDPOINT/my-nextjs-blog:latest
      docker push $REGISTRY_ENDPOINT/my-nextjs-blog:latest`
    • Update and apply a new container deployment:

      export CONTAINER_ID=$(scw container container list name="my-nextjs-blog" -o json | jq -r '.[0].id')
      scw container container deploy $CONTAINER_ID
    • The new version is live a few seconds later.

  • Inspect your newly created resources in the Scaleway console:

    • You can display your Registry namespace and container image in the Container Registry section

    • You can display your Serverless Containers namespace and container deployment in the Serverless Containers section

    • You can display your Serverless SQL Database in the Serverless SQL Databases section

  • Fine-tune deployment options such as autoscaling, targeted regions, and more. You can find more information by typing scw container deploy --help in your terminal, or by referring to the dedicated documentation.

  • Change the security configuration for your container. It is currently public and anyone with the link can access it, but you can make it private to require authentication.

Troubleshooting

If you happen to encounter any issues, first check that you meet all the requirements.

  • You have installed and configured the Scaleway CLI. Running the scw account project get command should return the following output:
    ID example-7afa-4a5d-9f6c-27db072f1527
    Name default
    OrganizationID example-7afa-4a5d-9f6c-27db072f1527
    CreatedAt 1 year ago
    UpdatedAt 1 year ago
    Description -
    Tip

    You can also find and compare your Project and organization ID in the Scaleway console settings.

  • You have Docker Engine installed. Running the docker -v command in a terminal should display your currently installed docker version:
    Docker version 24.0.6, build ed223bc820
  • You have the right IAM permissions, specifically ContainersRegistryFullAccess, ContainersFullAccess and ServerlessSQLDatabaseFullAccess.
API DocsScaleway consoleDedibox consoleScaleway LearningScaleway.comPricingBlogCareers
© 2023-2024 – Scaleway