惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Jina AI
Jina AI
T
The Blog of Author Tim Ferriss
B
Blog
L
LangChain Blog
Y
Y Combinator Blog
美团技术团队
博客园 - 三生石上(FineUI控件)
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
G
Google Developers Blog
量子位
博客园_首页
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
C
Check Point Blog
D
Docker
小众软件
小众软件
The Cloudflare Blog
大猫的无限游戏
大猫的无限游戏
T
Tailwind CSS Blog
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 聂微东
Blog — PlanetScale
Blog — PlanetScale
GbyAI
GbyAI
Google DeepMind News
Google DeepMind News
IT之家
IT之家

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
I Built a Django-Inspired Web Framework in Rust — Here's ...
itsuki · 2026-06-14 · via DEV Community

itsuki

If you've ever used Django, you know the feeling: one command, and you have an admin panel, an ORM, form validation, middleware, session handling — everything just works. Then you try Rust web development, and you're back to assembling pieces yourself.

That's why I built Runique: a batteries-included web framework for Rust, inspired by Django's philosophy, built on top of Axum and Tokio.


Why "Django for Rust"?

Existing Rust frameworks are excellent at what they do — Axum is fast and composable, Actix-Web is a performance beast — but they're low-level by design. You bring your own ORM, your own session store, your own CSRF protection, your own admin interface. For many projects, that's the right tradeoff.

Runique takes the opposite bet: convention over configuration, with a structured, opinionated setup that gets you from zero to a production-ready app fast, without sacrificing Rust's safety and performance.


The Builder: A Validated Construction Pipeline

The part I'm most proud of is the application builder. You declare your components with a fluent API — in any order — and then a single .build() call runs a fixed, validated construction pipeline at startup:

Validation → DB connection → Templates → Engine → Admin → Middleware → Static files

Here's what a typical app setup looks like:

let app = RuniqueAppBuilder::new(config)
    .routes(url::routes())
    .with_database_config(db_config)
    .with_mailer_from_env()
    .statics()
    .middleware(|m| m
        .with_session_memory_limit(5 * 1024 * 1024, 10 * 1024 * 1024)
        .with_session_cleanup_interval(5)
        .with_allowed_hosts(|h| h.enabled(true).host("example.com"))
        .with_csp(|c| c
            .policy(SecurityPolicy::strict())
            .with_header_security(true)
            .scripts(vec!["'self'", "'strict-dynamic'"]))
        .with_anti_bot())
    .with_admin(|a| a.routes(admins::routes("/admin")))
    .build()
    .await?;

app.run().await?;

The .build() call validates every component — including cross-dependencies — before constructing anything. If your SECRET_KEY is still the default insecure value in production, the build fails with a clear error and a fix suggestion, before a single request is served:

[Security] SECRET_KEY is using the default insecure value
  → Set SECRET_KEY to a random 32+ character string in your .env file

This is the Django check framework equivalent, but enforced at startup — not discovered in production.


Security Included by Default

Security in Runique isn't a plugin you add later. It's part of the construction pipeline itself:

  • CSP (Content Security Policy) — configurable profiles, per-request nonce, HTMX hash merging when the admin panel is enabled
  • CSRF protection — built into the middleware stack, with per-route exemptions
  • Host validation — allowed hosts checked before routing
  • Trusted proxies — explicit configuration, not implicit trust
  • Security headers on static filesX-Content-Type-Options, Strict-Transport-Security, X-Frame-Options, Referrer-Policy applied automatically
// You don't wire ServeDir yourself — `.statics()` does it,
// already wrapping every static/media route with security headers:
.statics()
// → X-Content-Type-Options: nosniff
//   Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
//   X-Frame-Options: DENY
//   Referrer-Policy: strict-origin-when-cross-origin
//   + cache-control

The middleware stack uses numbered slots to guarantee application order — you can't accidentally apply CSRF before sessions, because the slots enforce the correct sequence.


What's Included

  • ORM (via SeaORM, optional feature flag)
  • Template engine (Tera, with custom filters and a URL registry for named routes)
  • Admin panel (auto-generated from your models, merged before the middleware stack so it always has session/auth context)
  • Form engine (typed structs with validation, v2 in progress)
  • Session handling (memory-first store with database fallback, built on tower-sessions, with periodic cleanup)
  • i18n (the FR/EN bilingual doc site is itself built with Runique)
  • Middleware system with ordered slots
  • Password reset (pluggable, routes registered automatically during build)
  • Debug error page — a styled page with collapsible sections and copy-to-clipboard for stack traces

One Concrete Example: Admin Merge Order

Here's a subtle design decision that illustrates Runique's philosophy. In Axum, .layer() only applies to routes present at call time. This means if you merge your admin router after applying middleware, the admin routes run without session, CSRF, or extension context — a silent, hard-to-debug failure.

Runique handles this in the builder:

// Step 4b: admin + password reset — merged BEFORE the middleware stack.
// `.layer()` in Axum only covers routes present at call time;
// merging after means admin routes run without Session/CSRF/Extensions.
let router = if self.admin.enabled {
    router.merge(admin_router)
} else {
    router
};

// Step 5: middleware applied AFTER, covering everything including admin
let (router, session_store) = middleware.apply_to_router(router, config, engine, tera);

You don't have to think about this. The pipeline handles it.


Current Status

Runique is at v2.1.x, MIT licensed, with bilingual documentation (EN/FR) at runique.io.

The framework is used in production for a restaurant management system — dogfooding at its most direct.

What's missing (being honest here, Django-style):

  • No async task queue yet (background jobs run on bare tokio::spawn)
  • Email sending is partial
  • OAuth is planned but not yet implemented
  • Test coverage is at ~61% (growing)

Try It

Add the dependency to your Cargo.toml:

[dependencies]
runique = "2.1"

Read the Getting Started Guide

Links & Resources

Runique — Django-inspired Rust Framework

Rust Tests passing License Version Crates.io Runique

Runique is a web framework built on Axum, focused on type-safe forms, security middleware, template rendering, ORM integration, and a code-generated admin workflow.

Current state: active development. The framework source of truth is the runique crate demo-app is used as a validation/testing application for framework behavior.

🌍 Languages: English | Français


What this repository contains

  • runique/ → framework crate (main product)
  • demo-app/ → test/validation app for framework development
  • docs/ → EN/FR documentation

Workspace version (source of truth): 2.1.16.


Core capabilities

  • Type-safe form system (forms, extractors, validators, renderers)
  • Routing macros and URL helpers
  • Tera template integration and context helpers
  • Security middleware (CSRF, CSP, allowed hosts, sanitization, auth/session)
  • SeaORM integration + migration tooling
  • Flash message system
  • Admin beta (admin! macro + daemon-generated CRUD code)

Main public modules are exposed from runique/src/lib.rs.


Installation

git clone https://github.com/seb-alliot/runique
cd runique
cargo build --workspace
cargo 

What do you think?

I'm particularly curious to hear from:

  1. Django developers — Does this structure feel familiar, or "too much" for the Rust ecosystem?
  2. Rust experts — How would you handle the middleware ordering differently?

Let's discuss in the comments!