Skip to content

aidrecabrera/flint

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

flint

MIT License Copier uv Ruff

A Copier template I wrote for myself for starting Python backend projects.

copier copy gh:aidrecabrera/flint my-project --trust

This exists because scaffolding is annoying. I got tired of burning time on the same setup work over and over:

None of this is hard. It is just repetitive. And repetitive setup work is a good way to waste time and still end up with something inconsistent.

So I wrote the template I wanted to keep using myself.

It is also inspired by the backend structure in Polar, especially the idea of keeping things organized around FastAPI modules, auth-aware routing, and a backend layout that is practical instead of decorative.


Quick start

Prerequisites

You need the following installed on your system before using this template:

  • uv - install with:
    # macOS / Linux
    curl -LsSf https://astral.sh/uv/install.sh | sh
    
    # Windows
    powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.sh | iex"
  • just - install with:
    # macOS
    brew install just
    
    # Linux
    curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin
    
    # or via cargo
    cargo install just
  • Docker (optional) - only needed if you choose PostgreSQL or enable Docker for the app. Install via Docker Desktop or your system package manager.
  • Copier - install with:
    uv tool install copier

Generate a project

copier copy gh:aidrecabrera/flint my-project --trust

Set up

cd my-project
cp .env.example .env

If you chose PostgreSQL:

just db

Install dependencies:

just install

If the project uses a database:

just revision "initial"
just migrate

Start the app:

just dev

Then open:


What this is

This template generates a FastAPI project with a few defaults already decided.

You choose:

  • whether the project uses a database
  • whether it uses JWT auth
  • whether the app itself should be containerized with Docker

If you choose PostgreSQL, the generated project also includes Docker Compose for local database development.


Why I did this

Because scaffolding is painful.

Every time I start a backend project, I end up doing the same things:

  • making the same files
  • writing the same commands
  • checking the same docs
  • fixing the same annoying setup details
  • deciding the same tool choices again even though I already know what I want

That is dumb.

The question I asked myself before writing this template:

XKCD 1205 - Is It Worth the Time?

XKCD 1205 - on whether automating repetitive work is worth the upfront effort.

spoiler

yes

Then, naturally:

XKCD 974 - The General Problem

XKCD 974 - the developer instinct to solve the fully general version of a specific problem instead of just doing the specific thing.

The point of a project template is not magic. It is just refusing to redo boring work badly.

So this template makes the boring decisions once and keeps them out of the way.


What gets generated

Every generated project includes:

If you enable a database, it also includes:

If you enable auth, it also includes:

If you choose PostgreSQL, it also includes:

  • a docker-compose.yml with a local postgres service
  • just db, just db-stop, and just db-logs

If you enable Docker for the app, it also includes:

  • a Dockerfile
  • an app service in docker-compose.yml

What is fixed

These choices are not configurable:

If you do not want these specific choices, this is the wrong template for you. Popular alternatives include:

That is fine. Use something else, or fork this and change it.


What you choose

The template only asks for the things that actually change the project:

  • database: none, sqlite, or postgres
  • auth: none or jwt
  • docker: true or false

What the generated project looks like

A typical generated project looks like this:

project/
├── app/
│   ├── main.py
│   ├── config.py
│   ├── errors.py
│   ├── routers/
│   │   └── health.py
│   ├── db.py
│   ├── dependencies.py
│   ├── models.py
│   └── auth/
│       ├── models.py
│       ├── schemas.py
│       ├── utils.py
│       ├── dependencies.py
│       └── routes.py
├── tests/
├── alembic/
├── .github/workflows/ci.yml
├── .env.example
├── .python-version
├── justfile
├── pyproject.toml
├── README.md
└── docker-compose.yml

The exact files depend on the options you chose.


Commands in generated projects

Always available:

just install
just dev
just test
just lint
just fmt
just typecheck
just check

If the project uses a database:

just revision "message"
just migrate
just downgrade

If the project uses PostgreSQL:

just db
just db-stop
just db-logs

If the project includes app Docker support:

just up
just down
just logs

The DIY part

This template does not eliminate thinking. It just removes setup repetition.

You still have to do the real work yourself.

That includes:

  • deciding your actual domain model
  • writing real routes
  • designing your schema properly
  • reviewing generated migrations before applying them
  • changing defaults that are wrong for your app
  • setting a real SECRET_KEY
  • deciding how you want to deploy
  • deciding whether you really want JWT auth or something else
  • organizing the code further if the project grows
  • deleting parts you do not need

If you picked auth, you should understand the auth code.

If you picked a database, you should understand the models and migrations.

If you picked Docker, you should understand what the container is doing.

The template gives you a working starting point. It does not absolve you from knowing what you are running.

That would be a stupid way to build software.


A few decisions worth mentioning

FastAPI

This follows the FastAPI docs fairly closely, especially around:

SQLModel

I like SQLModel, so it is the default when a database is enabled.

This means there is no ORM choice in the template. If I wanted plain SQLAlchemy instead, I would use a different template.

Sync DB sessions

This uses sync SQLModel sessions, the default in the official FastAPI + SQLModel docs. FastAPI runs sync dependencies in a threadpool, so this works fine for most backends.

SQLModel does support async, but the official async documentation is still minimal (it is listed as a planned feature in the Advanced User Guide). It also adds real complexity (extra drivers, greenlet, and frequent MissingGreenlet errors with lazy loading).

If you need async support, swap create_engine to create_async_engine and Session to AsyncSession (from sqlmodel.ext.asyncio). The rest of the app stays mostly the same.

Alembic

Alembic is included and configured so migrations work immediately.

That does not mean you should blindly trust autogenerated migrations. Read them.

No custom logging

There is no logging setup in the template beyond what FastAPI and the server already do.

No Redis, Celery, Sentry, etc.

Not because those tools are bad. They just do not belong in the base template I want.

If a project needs them, add them: YAGNI.


Updating generated projects

Because this uses Copier, generated projects can be updated later:

copier update --trust

I care about this mostly because I want to keep using the template myself and pull improvements back into projects created from it.

If you use the template too, you can do the same.

Copier update docs


Useful references

These are the main docs this template is based on:


If you use it

Fork it. Change it. Remove things you do not like.

Contributing

This is mainly a personal template that I open-sourced. Issues, PRs, and suggestions are welcome, especially if you find bugs or have ideas that would make the defaults better.

License

This template is licensed under the MIT License. See the LICENSE file for details.

About

Copier template for FastAPI backends with uv, SQLModel, JWT auth, and Docker.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors