Self-hosted service
Aeternalis-Ingenium/FastAPI-Backend-Template avatar
Aeternalis-Ingenium/FastAPI-Backend-Template

FastAPI-Backend-Template decides the boring parts for you

A backend project template with FastAPI, PostgreSQL with asynchronous SQLAlchemy 2.0, Alembic for asynchronous database migration, and Docker.

884 stars130 forksPythonGPL-3.0

At a glance

What is it?
Aeternalis-Ingenium's FastAPI-Backend-Template is a starting point for a Python API with asynchronous PostgreSQL through SQLAlchemy 2.0, Alembic migrations that run asynchronously, Docker Compose for the database, a database editor and the app, and a .env file that exposes every knob including the JWT settings and the connection pool. The README is explicit that it is a template, and the branch is called trunk.
Who is it for?
Adopt FastAPI-Backend-Template if you are starting a Python API with FastAPI and want the asynchronous database layer, the migration setup, the container orchestration and the linting and test harness already arranged, and if you are willing to delete the example Account model.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A template, and the README says so

The project says it is a template repository aimed to kick-start your project with a setup from a real-world application, and the three technologies it names are Dockerized, Asynchronous PostgreSQL and FastAPI.

The audience is a developer starting a Python API and facing the same set of decisions every time. Which web framework, sync or async database access, how migrations run, how the dev environment is started, how the linting and the tests are wired, how secrets and settings are loaded. The template's value is that those answers are already written down and, more importantly, already working together, so the first hour of a new project is spent on the application rather than on the plumbing.

The justification the README gives for the stack is blunt: the easy answer is asynchrony and speed. FastAPI is described as the fastest web framework for Python, the database is the asynchronous version of PostgreSQL reached through SQLAlchemy 2.0, and Docker is described as packaging an application into standardised units that have everything the software needs to run including libraries, system tools, code and runtime.

The workflow choice is stated too, and it explains the branch name. The author prefers trunk based development because of the straightforward approach in the collaboration workflow, hence the name trunk for the main branch repository instead of master or main. The default branch is trunk, and the CI badge points at a workflow called ci-backend.yaml, so the naming is consistent.

The licence is GPL-3.0, the last push was on 2026-10-19, and the repository publishes no GitHub releases, which is the right shape for a template.

The code layout separates the four layers of a CRUD service

The section on what code is included is the most useful part of the README, because it shows the shape of a service rather than a feature list.

There is a settings layer. The project, linter and test configurations live in backend/pyproject.toml, there are three settings classes for development, staging and production, with the super class in backend/src/config/settings/base.py, and an event logger in backend/src/config/events.py.

Then the models, in two kinds. The Account object table model is in backend/src/models/db/account.py, which is the SQLAlchemy side, and the Account object schema model is in backend/src/models/schemas/account.py, which is the Pydantic side. That split is the important convention: the database model describes the table and the schema model describes what goes over the wire, and they are allowed to differ.

Then the repository layer. The PostgreSQL connection with asynchronous SQLAlchemy 2.0 is in backend/src/repository/database.py, there is a custom SQLAlchemy Base class in backend/src/repository/table.py, database related events such as table registration by app startup are in backend/src/repository/events.py, the C R U D methods for the Account object are in backend/src/repository/crud/account.py, and the table classes registration file is in backend/src/repository/base.py.

Finally the API layer, with dependency injection for the database session and repository under backend/src/api/, and the endpoints for Account signup and signin in backend/src/api/routes/authentication.py, plus endpoints for get all, get one, update and delete in the same area.

The convention is worth copying whatever else you do with the template. The database, the HTTP layer and the route handlers never import each other directly. The route asks for a repository through dependency injection, the repository talks to the ORM, and the models sit on both sides of that boundary as separate classes.

Alembic, but configured for async

The migration story is the part of the template that is easy to get wrong by hand, and it is handled explicitly.

The README lists Alembic setup for auto-generating asynchronous database migrations in backend/src/repository/migration/, and the Alembic main configuration file in backend/alembic.ini. The word asynchronous is doing the work there. A stock Alembic setup runs its migration environment synchronously, which means it opens a synchronous connection to Postgres while the application itself runs on an async engine, and that combination is where the classic cannot run inside a transaction and event loop errors come from.

The template solves that by putting the migration environment inside the repository layer, next to the async engine it is meant to migrate, rather than in a separate top level directory. The alembic.ini lives at the backend root while the environment code sits under the repository.

The other supporting pieces are in the same tree. The database related events in backend/src/repository/events.py handle things such as registering the tables when the app starts up, and the custom Base class in backend/src/repository/table.py is what those registrations hang off.

For a team that has never run Alembic against an async engine, this is the part of the template that will save the most time. For a team that has, it is still a reasonable default, and the reason to keep it rather than write your own is that the environment is already wired to the same session factory the application uses.

Three containers, and the ports are worth knowing

The docker-compose.yaml defines three services, and the README lists the addresses you get when the stack is up: the backend application with its API docs at http://localhost:8001/docs and the database editor, Adminer, at http//localhost:8081, while the backend API without Docker can be found at http://localhost:8000/docs.

The database service is a plain Postgres image with the credentials taken from the environment, a named volume for the data directory, and the port mapped from 5433 on the host to 5432 in the container:

yaml
version: '3.9'

services:
  db:
    image: postgres:latest
    container_name: db
    restart: always
    environment:
      - POSTGRES_USER=${POSTGRES_USERNAME}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_DB=${POSTGRES_DB}
      - PGDATA=/var/lib/postgresql/data/
    volumes:
      - postgresql_db_data:/var/lib/postgresql/data/
    expose:
      - 5432
    ports:
      - 5433:5432

The Adminer service is a separate container on the adminer image, exposed on 8080 and published on 8081, with a depends_on entry pointing at the database, and the backend service is built from a Dockerfile with the context at the backend directory, with its whole configuration injected through environment variables.

Two things stand out. The database port is remapped to 5433 on the host rather than the default 5432, which avoids a clash with a Postgres you already run locally. And every service has restart: always, which for a development stack is a reasonable default and for anything else is a decision to revisit.

The environment file is where the real configuration lives

The .env.example at the root is the most instructive file in the repository, because it shows every decision the template makes explicit rather than hiding in code.

The server section is small:

bash
ENVIRONMENT=DEV
DEBUG=True
BACKEND_SERVER_HOST=127.0.0.1
BACKEND_SERVER_PORT=8000
BACKEND_SERVER_WORKERS=4

The database section covers the Postgres connection and the SQLAlchemy engine, including the pool sizes and the flags that change engine behaviour, such as whether to echo the log, whether to expire on commit and whether to force a rollback:

bash
DB_TIMEOUT=5
DB_POOL_SIZE=100
DB_MAX_POOL_CON=80
DB_POOL_OVERFLOW=20
IS_DB_ECHO_LOG=True
IS_DB_EXPIRE_ON_COMMIT=False
IS_DB_FORCE_ROLLBACK=True

And then the authentication settings, with the token lifetimes expressed in minutes, hours and days, and a hashing configuration that layers bcrypt and argon2:

bash
JWT_SECRET_KEY=YOUR-JWT-SECRET-KEY
JWT_SUBJECT=YOUR-JWT-SUBJECT
JWT_TOKEN_PREFIX=YOUR-TOKEN-PREFIX
JWT_ALGORITHM=HS256
JWT_MIN=60
JWT_HOUR=23
JWT_DAY=6

The last two lines of the environment example set the hashing algorithm layer one to bcrypt and layer two to argon2, and the salt is a placeholder. Two layers of hashing is not a standard pattern, and it is worth understanding what the template intends before you keep it.

The rest of the file holds the database credentials, the API and authentication tokens, the Postgres URI template with the schema, username, password, host and port, and the Codecov token, which the README says you get by logging in to Codecov.

Everything in that file is a placeholder, and the JWT secret in particular is the one to change before anything else, since a default secret in a template is a default secret in production.

The quality toolchain is the other half of the template

The README lists a long set of supporting technologies, and they are worth reading as a set rather than a list, because together they describe what a team gets for free.

Pre-commit is the mechanism, with git hook scripts that identify issues in the code before it is pushed, and three linters behind it. Black manages code style with auto-formatting, isort sorts the imports for clarity, and mypy is the static type checker. There is also pre-commit.ci, which the README describes as continuous integration for the Pre-commit hook that fixes and updates the hook versions, which solves the problem of a hook configuration that is never upgraded.

Pytest is the testing framework, and CodeCov is the platform that analyzes the result of the automated tests, with a codecov.yaml at the root of the repository and a badge in the README. GitHub Actions is the CI/CD platform, and the workflow file is the ci-backend.yaml one the badge points at.

The configuration choices are TOML for the project, linter and test configuration, and pyenv with pyenv-virtualenv for managing Python versions and the virtual environments, which the README calls the simplest way to manage your Python versions and the plugin for managing the virtual environment for your packages. DBDiagram is there for designing the database by writing SQL and converting it into an entity relationship diagram, and CODEOWNERS is a file for distributing the responsibilities in the project to each team member.

The badges confirm the whole stack: pre-commit enabled, code style black, imports isort, a mypy check, coverage on Codecov, and the CI workflow status.

So the answer to the question a new team actually asks, which is what happens when someone pushes code, is that a set of hooks runs locally, the same checks run again on GitHub Actions, and the coverage is tracked. That is a defensible default for a template, and it is also the first thing you will want to relax if your project is not a service.

Editorial conclusion

Adopt FastAPI-Backend-Template if you are starting a Python API with FastAPI and want the asynchronous database layer, the migration setup, the container orchestration and the linting and test harness already arranged, and if you are willing to delete the example Account model. Do not adopt it if you want a synchronous stack, since the async SQLAlchemy and async Alembic choices are the point of the template and reversing them is a rewrite, and do not adopt it expecting a maintained framework, since there are no releases and the project describes itself as a template to kick start your project. Before you build on it, replace every placeholder secret in the environment file, check the Alembic setup under the migration directory, and look at the trunk based development choice, because the branch layout is deliberate and differs from the master or main convention.

Frequently asked questions

What is the FastAPI-Backend-Template repository?

It is a project template aimed to kick-start a project with a setup from a real-world application, using Dockerized development, asynchronous PostgreSQL and FastAPI, with Alembic for asynchronous migrations and a full set of configuration, linting and testing tooling.

How is the code organised in the FastAPI backend template?

The settings live in backend/src/config with a base class plus development, staging and production subclasses, the database model and the API schema model are separated under models/db and models/schemas, the repository layer with the async SQLAlchemy connection, the Base class and the CRUD methods lives under repository, and the routes with dependency injection live under api.

What does docker-compose.yaml in the template start?

Three services: a Postgres database with a named volume, mapped from host port 5433 to 5432, an Adminer database editor published on 8081, and the backend application built from the backend directory and configured entirely through environment variables.

Which settings does the template's environment file expose?

Server settings for environment, debug, host, port and worker count, the Postgres connection details and URI template, the SQLAlchemy pool and engine flags such as DB_POOL_SIZE and IS_DB_FORCE_ROLLBACK, JWT settings including the algorithm and the minute, hour and day lifetimes, the layered hashing algorithm configuration, and the API and authentication tokens.

Why is the default branch called trunk?

The README explains that the author's preferred workflow is trunk based development, for the straightforward approach in the collaboration workflow, hence the name trunk for the main branch instead of master or main. The licence is GPL-3.0 and the repository publishes no GitHub releases.

Official sources

  1. Aeternalis-Ingenium/FastAPI-Backend-Template on GitHub
  2. Issues
  3. License: GPL-3.0
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/aeternalis-ingenium-fastapi-backend-template.svg)](https://hysenlabs.com/projects/aeternalis-ingenium-fastapi-backend-template)

Was this useful?