Skip to content
On this page


You can self-host Briefkasten with Docker or manually by spinning up the Next.js app and Postgres on any host yourself. There are a few caveats to keep in mind with the self-hosted route, however. Depending on how okay you are with signing up for online services.

You can use any Postgres database you like, i.e. local, or hosted in the cloud. However, the object storage for bookmark screenshots is designed to work specifically with Supabase. That means, if you don't fill in the SUPABASE_* environment variables, you will not have dynamic bookmark screenshots. Otherwise, the app works just fine completely self-hosted, for example with the Docker setup described below!


You can host the Briefkasten application entirely on your own via the included docker files.

This will result in your hosting two items:

  1. The Briefkasten Next.js application
  2. The companion PostgreSQL database

Make sure you have docker and docker-compose installed.

Getting Started

  1. Clone the repository to your server.
git clone
  1. Setup the environment variables.

Make a copy of the .env.example file and fill in at least the required variables with your favorite text editor. The example file has annotations for the variables.

cp .env.example .env
vim .env


When using the local postgres container you should set the DATABASE_URL environment variable to DATABASE_URL=postgres://bkAdmin:briefkasten@postgres:5432/briefkasten?sslmode=disable

  1. Start the docker-compose stack of applications
docker-compose up -d
  1. Setup the database

After starting the containers, you still have to manually apply the database schema. This is most easily done through the app container (bk-app).

docker exec -it bk-app /bin/bash

// Inside the 'bk-app' container
pnpm db:push
  1. Now your application and database should be up and running at the default http://localhost:3000!

You can continue by putting localhost:3000 behind a reverse proxy (i.e. nginx) which can terminate TLS for you (https) and provide access via a nice domain name of your choice. For more details, check out the Linode guide on setting up a reverse proxy with nginx.


To manually selfhost Briefkasten there are 3 required prerequisites and 1 optional one. The required items are as follows:

  1. A platform to host a Node.js (Next.js) application
  2. A Prisma compatible database (SQLite, Postgres, Mysql, etc.)
  3. An authentication provider
  4. S3-like object store (optional)

Next.js Hosting

To run the actual Briefkasten application itself, you will need some sort of platform to run a Node.js 16 application on. This can be any sort of server you have access to, or a hosting platform like Vercel or Netlify. I won't go into a ton of detail here, I will assume you know how to run a node.js application and/or can setup a Vercel account if you're going to be selfhosting software.

Some things to remember here, however, are the environment variables. You will need to make sure your hosting platform has a copy of your production environment variables. Including the production NEXTAUTH_URL and NEXTAUTH_SECRET. As well as a production DATABASE_URL.

The OAuth credentials can be acquired through the instructions on the NextAuth.js site. Don't forget to set the provider clientId/secret of your choice (i.e. GITHUB_ID/GITHUB_SECRET).

Finally, if you've opted into providing an object storage provider for bookmark images, the application is currently setup to use Supabase only. Therefore, you can pass your secrets as SUPABASE_URL and SUPABASE_KEY. Make sure to use the service account key which has write rights. More details below for using a different object storage provider.


The image uploading functionality will be skipped over entirely if you do not pass a SUPABASE_URL environment variable. No other action is necessary.


For the database portion, you must simply provide some write permissioned credentials to any type of database supported by Prisma, preferably not MongoDB. This setting is applied primarily through the passing of the DATABASE_URL which should contain all the details to connect, such as hostname and username/password. This environment variable is passed through to Prisma in its prisma/schema.prisma file. Currently this file is setup for Postgres, therefore, if you plan to use a different type of database, **you must change the db.provider value in that file from postgres to whichever type you want.

After setting up your database credentials, you can run the following command to apply all migrations and prepare the database for the application.

pnpm dlx prisma migrate dev
# or
npx prisma migrate dev

After this, the database should be ready to receive new users and bookmarks from the application!


For authentication, I've opted to use the NextAuth.js library, as I help maintain the project and am intimately familiar with it. Setup is extremely easy and I've prepared Briefkasten for the following 3 login types. You must use at least one and at most all 3. Although you can obviously adjust the code to add any more that you may wish to use.

The two OAuth providers are setup simply by passing their respective clientId and secret's via environment variables. The email magic link provider requires just an SMTP connection string, similar to the DATABASE_URL connection string used previously. It should contain the SMTP host, username and password, port, etc. and can be supplied via the SMTP_SERVER environment variable.

Object Storage

As previously mentioned, the object storage is optional, and used only for storing bookmark screenshots. The application with function just fine without bookmark images, however, in my opinion it will be much less nice 😃

Briefkasten is setup to use Supabase and their Storage product. You can sign-up for a free Supabase account at their website and use the 1GB free storage they provide you. As mentioned in the hosting section, you then simply need to pass the SUPABASE_URL and SUPABASE_KEY as environment variables for it to work.

If you want to use a different object storage provider, there are a few changes you will need to make. Including swapping out the use of the supabase javascript sdk with your own object storage library, and replacing of the public bucket URL in a few places.

First, in /src/pages/api/bookmarks/index.js, on L184 we are using the supabase sdk client to upload the screenshot blob returned from the Briefkasten screenshot API. On L394 we are using the same sdk client in the DELETE endpoint handler to delete images when their bookmark is deleted as well.

Secondly, in the /src/pages/api/bookmarks/uploadImage.js on L25 in the PUT handler, we are uploading the body of the PUT request (which should be a base64 encoded image) to Supabase using their sdk client.

Those are the only usages of the sdk client which you would theoretically need to replace with the upload logic of another object storage provider.

In addition, there is hard coded the prefix of my Supabase bucket URL in a few places in the codebase. If you search for, you will find all places (4) which need to be replace with the URL / static part of the URL of your new provider. Be aware the bucket must be public, or you must also add code to authenticate reads.