Next.js with Thin

Learn how to add Thin to your Next.js application

1. Introduction

This guide covers how to use Thin as the Backend for your Next.js application.

If you haven't already, start by generating a new Next.js project:

npx create-next-app@latest --typescript

Using TypeScript for the project is highly recommended, as Thin Backend provides type definitions for your project.

Now you can start the Next.js development server:

npm run dev

2. Install Packages

To use Thin Backend install the thin-backend and thin-backend-react packages into your project:

npm install thin-backend thin-backend-react

3. Init

Now that we have installed the Thin Backend packages, we need to call initThinBackend from pages/_app.tsx and wrap the app with <ThinBackend>.

import '../styles/globals.css'
import type { AppProps } from 'next/app'
import { initThinBackend } from 'thin-backend';
import { ThinBackend } from 'thin-backend-react';

initThinBackend({ host: process.env.NEXT_PUBLIC_BACKEND_URL });

function MyApp({ Component, pageProps }: AppProps) {
  return <ThinBackend requireLogin>
    <Component {...pageProps} />
  </ThinBackend>
}
export default MyApp

The <ThinBackend requireLogin> in the above code makes sure that the user is logged in. If the user is not logged in yet, it will redirect to the login page.

You can see that we use process.env.NEXT_PUBLIC_BACKEND_URL in the above code. We also need to define this. Create a new .env file and put this into the file:

NEXT_PUBLIC_BACKEND_URL=https://<YOUR PROJECTS BACKEND_URL>

Important Note: While Thin Backend typically uses the BACKEND_URL env variable, in Next.js projects we need to prefix it with NEXT_PUBLIC_, otherwise the env var is not available at build-time.

Restart the npm run dev server, so that the new env var is loaded.

Now the Next.js application is connected to your Thin Backend and you can now use Thin Backend for accessing your database and managing auth.

4. Installing Types (Optional)

Thin Backend generates TypeScript Type Definitions based on your database schema. This catches most runtime errors ahead of time, while providing really nice autocompletion in VSCode and other editors.

The custom Types can be installed into a project by installing a custom npm package. This npm package is specifically generated for your project and tagged with a secret url, so only you can access it.

To install your project's Types, open the Schema Designer. Click the Type Definitions tab. Now you see a npm install .. command:

Run this command locally in your project directory. After that the types will be automatically available in your project.

When you make changes to the database schema, a new type definition package will be generated. To use the latest types, open the Type Definitions tab again and install the latest package listed there.

5. Retrieving the Current User

A good starting point is to display the current logged in user and a logout button in your app. You can use useCurrentUser() for this:

// Add these imports:
import { logout } from 'thin-backend';
import { useCurrentUser } from 'thin-backend-react';

function UserStatus() {
    // Use the `useCurrentUser()` react hook to access the current logged in user
    const user = useCurrentUser();

    return <div>
        {user?.email}

        <button onClick={logout}>Logout</button>
    </div>
}

// Don't forget to mount the `<UserStatus/>` component from somewhere
// in your app, e.g. the `pages/index.tsx`:

const Home: NextPage = () => {
  return (
    <UserStatus/>
  )
}

The logout function used in the onClick is provided by Thin Backend. It deletes the locally stored JWT for the current user session and then redirects the user back to the login page.

6. Fetching Data

You can use the useQuery hook to access your project's database. Let's say your building a todo list app and you've previously created a todos table in the Schema Designer. The following code will show all todos:

// Add these imports
import { query } from 'thin-backend';
import { useQuery } from 'thin-backend-react';

function TodoList() {
    const todos = useQuery(query('todos').orderByDesc('createdAt'));

    if (todos === null) {
        return <div>Loading ...</div>;
    }

    return <div>
        {todos.map(todo => <div>{todo.title}</div>)}
    </div>
}

The useQuery(query('todos')) call in our TodoList sets up a subscription behind the scences. Whenever the result set of our query('todos') we fired here changes, it will trigger a re-render of our component.

7. Writing Data

You can call createRecord('sometable', someObject) insert something into your database:

// Add this import
import { createRecord, getCurrentUserId } from 'thin-backend';

function NewTodoButton() {
    function addTodo(event) {
        createRecord('todos', {
            title: window.prompt('Enter a title:') || '',
            userId: getCurrentUserId()
        });
    }

    return <button onClick={addTodo}>Add Todo</button>
}

Check out the Database Guide for a full list of all database operations you can do with Thin.

Next: Database Guide

Community

If you need any help or input, feel free to ask in the Thin Community Forum.

Check out the Next.js Template Project on GitHub:

Next.JS Template