Neolith, for Django · pre-alpha
Deploy Django apps, not Django projects.
A specification and Django library for running a Django app in a shared process or as its own service, switched by configuration, not code.
- status
- pre-alpha
- installable
- not yet
- specification
- draft 0.1
- latest release
- none yet
- license
- BSD-3-Clause
One project, one deployment
Django's app is a good unit of modularity, but its unit of deployment is the project.
A Django codebase therefore ships, scales and fails as one piece. Splitting it usually means several Django projects with duplicated settings and hand-written network calls, or a rewrite in a lighter framework that gives up the ORM, migrations and admin.
Make the app the unit of deployment
This is the design in the specification. The code has contracts and typed errors so far.
Each app declares the contracts it provides and requires, and Neolith's app host, the runtime that boots apps from their declarations, runs it attached, in a shared process, or detached, as its own service. The mode is deployment configuration: neither the app nor its callers change.
How it works
Every call between apps goes through a contract, a connector and a transport.
- contract
- An app's only public surface: named, versioned actions with typed requests, replies and errors, such as
inventory.v1. - connector
- What a caller gets from
connect(). It picks a provider of the contract and hands the call to a transport. - transport
- What carries the call: in-process when attached, HTTP when detached, or another conformant transport.
What you can check today
Neolith is pre-alpha, so the evidence is the written record and the tests, not production use.
| Evidence | What it shows | Status | Where |
|---|---|---|---|
| Specification | How apps declare contracts, how calls travel and how an app boots alone, with no Django or Python in it. | Fact: draft 0.1. Five of its seven documents are still outlines. | Specification (opens another site) |
| Design decisions | Each choice that shapes the architecture, with the options weighed and the consequences. | Fact: 15 accepted and 8 proposed. | Decision records (opens another site) |
| Requirement trace | Each normative statement has an ID, and CI reports which ones a passing test covers. | Fact: enforced for the contracts document; others join as their roadmap steps land. | Test rules (opens another site) |
| CI matrix | The tests on Django 5.2 with Python 3.12 and Django 6.1 with Python 3.15, on x86-64 and arm64. | Fact: runs on every pull request, with deprecation warnings as errors. | CI runs (opens another site) |
| Contracts in code | @contract, @action, @implements and ContractError; a contract and its implementation are checked when their module is imported. | Fact: on main, not released. | Changelog (opens another site) |
| Conformance suite | Every contract test run over the in-process and the HTTP transport, with identical results. | Plan: roadmap step 6. | Conformance (opens another site) |
| App boots alone | neolith run <app> starting one app with only what it declares, shown in CI. | Plan: roadmap steps 4 and 8. | Roadmap (opens another site) |
Not solved yet
- How the admin and Django's other contrib apps run across hosts.
- Authentication between apps in production. The only credential the specification requires so far is a shared-secret token meant for development.
- Consistency across apps without shared transactions. It relies on events, which are deferred past 0.1.
- Moving an app's data when it detaches, also deferred past 0.1.
- Changing an app's mode at runtime, without a redeploy.
What Neolith asks of an app, such as owning its data, is in the FAQ.
Get started
Nothing is installable yet. The first release, 0.1, is still being built.
- Read the overview and terms (opens another site), the first document of the specification.
- Read the vision (opens another site) and the guiding principles (opens another site) to see the trade-offs.
- Follow the roadmap (opens another site) and watch the repository (opens another site) for the first release.
Planned public surface, abridged from the roadmap. Not installable yet.
from typing import Protocol
from neolith import NeolithAppConfig, contract, action, implements, connect, ContractError
@contract("inventory.v1")
class Inventory(Protocol):
@action(idempotent=True)
def reserve(self, request: ReserveRequest) -> ReserveReply: ...
@implements(Inventory)
class InventoryImpl:
def reserve(self, request: ReserveRequest, ctx: CallContext) -> ReserveReply: ...
class InventoryConfig(NeolithAppConfig):
name = "inventory"
provides = ["inventory.v1"]
requires = []
resources = {"database": "inventory"}
# in a caller
inventory = connect("inventory.v1")
try:
reply = inventory.reserve(ReserveRequest(sku="A1", qty=2))
except ContractError as e:
e.kind # "unavailable", "conflict", ...contract, action, implements and ContractError are in the code on main; connect and NeolithAppConfig are not yet. In 0.1, neolith run <app> is planned to boot one app on SQLite, with support planned from Django 5.2 LTS on Python 3.12 up to Django 6.1 on Python 3.15.
Contribute
The spec and the code are written together, so design discussion is as useful as code right now.
- Contributing guide (opens another site)The numbered rules every pull request is reviewed against.
- Issues (opens another site)Questions and bugs; open one before any change beyond a small fix.
- Good first issues (opens another site)The label for starter tasks; small, obvious fixes need no issue first.
- Open questions (opens another site)What still needs research or a decision.
- Roadmap (opens another site)The eight steps to 0.1 and what each delivers.
- Security (opens another site)Report a security issue privately here, not in a public issue.
Neolith is licensed under BSD-3-Clause, the same license as Django. Read the FAQ.
Neolith is not affiliated with or endorsed by the Django Software Foundation.