Zestminds

FastAPI Project Structure: Production-Ready Architecture Guide

A scalable FastAPI system depends heavily on how the project is structured. A production-ready FastAPI architecture separates routing, business logic, database access, configuration, testing, and background processing into clear layers so teams can maintain and scale APIs without turning the codebase into technical debt.

This guide explains practical FastAPI architecture patterns used in real backend systems, including layered architecture, feature-based organization, dependency injection, repositories, configuration, testing, and scaling decisions.

Shivam Sharma
By Shivam Sharma Updated April 27, 2026

What Is the Best FastAPI Project Structure?

The best FastAPI project structure separates API routes, business logic, database access, schemas, configuration, and tests into clear responsibilities. A typical production-ready FastAPI backend includes routers for HTTP endpoints, services for business workflows, repositories for database queries, schemas for request and response validation, and core modules for configuration and infrastructure concerns.

app/
 ├ main.py
 ├ api/
 ├ services/
 ├ repositories/
 ├ models/
 ├ schemas/
 ├ core/
 └ tests/

This layered architecture helps teams scale FastAPI applications without turning the codebase into a messy monolith.

Before designing a scalable FastAPI backend, teams should standardize the runtime environment, dependency management, configuration style, and deployment path. If you are setting up a new project, start with the FastAPI requirements and setup guide.

When developers first start using FastAPI, the experience feels refreshingly simple.

You create a main.py, define a few endpoints, and within minutes you have a working API. It is one of the reasons FastAPI has become a favorite for backend APIs, SaaS platforms, AI products, internal tools, and high-performance web services.

But something interesting happens as the API grows.

  • New endpoints appear.
  • Authentication gets added.
  • Database logic expands.
  • Background jobs quietly join the system.
  • External integrations start depending on the same workflows.

And suddenly the codebase that once felt elegant starts feeling messy.

At this point, the issue usually is not the framework.

It is the project structure.

A poorly structured FastAPI backend becomes harder to maintain, harder to test, and harder for new developers to understand. A well-designed structure allows teams to move faster even as the system becomes more complex.

In practical terms, a FastAPI project structure is the architectural layout that separates routers, services, repositories, models, schemas, configuration, tests, and infrastructure modules so the backend remains maintainable as the API grows.

The goal here is not a beginner tutorial. The goal is to explain practical structure and real-world architecture decisions that keep FastAPI projects maintainable over time.

Why FastAPI Project Structure Matters

Every API starts small.

Most developers write something like this:

from fastapi import FastAPI

app = FastAPI()

@app.get("/users")
def get_users():
    return db.query(User).all()

For a prototype, this is completely fine.

But imagine the same API six months later.

Now the system includes authentication, permissions, integrations, analytics processing, caching layers, background jobs, scheduled tasks, and hundreds of endpoints. The codebase that once lived comfortably in a single file is now spread across multiple modules.

Without a clear backend structure, problems begin to appear.

Common structural problems teams encounter as FastAPI projects grow

  1. Router files grow to hundreds of lines.
  2. Business logic gets mixed directly with API endpoints.
  3. Database queries appear inside route handlers.
  4. Validation and workflow logic gets repeated across endpoints.
  5. Background jobs need logic that currently exists only inside routers.
  6. New developers struggle to understand where code belongs.

Routers Slowly Become Overloaded

One of the most common issues in growing FastAPI projects is routers doing too much work.

Instead of simply handling HTTP requests, routers start managing:

  • database queries
  • business rules
  • validation logic
  • integration calls
  • transaction decisions

At first this feels convenient. But as the file grows, endpoints become harder to read, harder to test, and harder to debug.

Experienced founders and engineering leads often notice this moment when reviewing their codebase. The router file becomes the place where everything happens. That is usually a signal the architecture needs attention.

Business Logic Starts Getting Duplicated

Consider a user creation workflow.

If that logic exists only inside the router, what happens when the same logic is needed elsewhere?

For example:

  • background jobs
  • import scripts
  • admin tools
  • batch processing
  • third-party integrations

Developers either duplicate the logic or move it later under pressure. Both approaches create friction.

A clean FastAPI backend architecture avoids this by giving business logic its own home.

Collaboration Gets Harder

As teams grow, structure matters even more.

New developers joining the project will inevitably ask:

  • Where should database logic live?
  • Where should authentication logic go?
  • Where should shared utilities be added?
  • Where should background tasks be placed?
  • Where should feature-specific logic belong?

If the project structure is unclear, everyone starts solving the problem differently.

Over time, the codebase becomes inconsistent.

Separation of Concerns Solves This

A well-designed FastAPI backend architecture introduces clear boundaries.

Each layer focuses on a single responsibility.

Think of a restaurant.

  • The waiter takes the order.
  • The chef prepares the meal.
  • The supplier provides ingredients.

If the waiter started cooking and sourcing ingredients, the restaurant would collapse quickly.

Backend architecture works the same way. Routers should not do everything. Services should not become database dumps. Utilities should not become a secret basement where random code goes to disappear.

Basic FastAPI Folder Structure

Before discussing advanced architectures, it helps to start with a simple structure that already encourages good habits.

A clean baseline for a scalable FastAPI folder structure often looks like this:

app/
 ├ main.py
 ├ routers/
 ├ services/
 ├ repositories/
 ├ models/
 ├ schemas/
 ├ core/
 ├ dependencies/
 └ tests/
FastAPI project structure example with routers, services, repositories and database layers
A well-organized FastAPI project separates API routes, business logic, database access, schemas, tests, and configuration modules.

This structure is simple enough for smaller teams but flexible enough to scale into a larger backend.

main.py — Application Entry Point

The main.py file initializes the FastAPI application.

Typical responsibilities include:

  • creating the FastAPI instance
  • registering routers
  • attaching middleware
  • loading application settings
  • configuring lifespan events

Example:

from fastapi import FastAPI
from app.routers import users

app = FastAPI()

app.include_router(users.router)

This file should remain small and predictable.

Think of it as the boot sequence of your backend, not the place where application logic lives.

What should stay inside main.py?

A production main.py should usually contain app-level setup, not business behavior.

Keep these inside main.py:

  • FastAPI app creation
  • router registration
  • middleware setup
  • exception handler registration
  • lifespan or startup configuration

Avoid putting these inside main.py:

  • database queries
  • business workflows
  • large route implementations
  • third-party integration logic
  • feature-specific validation logic

If main.py becomes a giant file, the project is usually drifting toward poor structure.

routers — API Interface Layer

Routers define the HTTP interface of the system.

Typical router modules might include:

routers/
  users.py
  auth.py
  orders.py

Routers should focus on four responsibilities:

  • receiving requests
  • validating input
  • calling services
  • returning responses

Nothing more.

If routers start containing business workflows, database queries, and integration logic, the architecture begins to blur.

services — Business Logic Layer

The services directory contains the behavior of the system.

Example structure:

services/
  user_service.py
  auth_service.py
  order_service.py

Services implement workflows such as:

  • registering users
  • authenticating sessions
  • processing orders
  • handling permissions
  • interacting with external APIs

This layer allows business logic to be reused across routers, background workers, admin tools, and scripts.

Many CTOs eventually realize this layer becomes the center of clarity in a backend architecture.

repositories — Database Access Layer

Repositories isolate database queries and persistence logic.

Example structure:

repositories/
  user_repository.py
  order_repository.py

Repositories usually handle:

  • fetching records
  • creating records
  • updating records
  • deleting records
  • query-specific database logic

This keeps services focused on business workflows instead of raw database operations.

models — Database Models

The models folder contains ORM models.

Example:

models/
  user.py
  order.py

These models define the database schema and relationships.

Keeping them isolated makes it easier to manage database migrations and schema evolution.

schemas — Request and Response Validation

Schemas define the data structures used by the API.

Example:

class UserCreate(BaseModel):
    email: str
    password: str

Schemas provide:

  • validation
  • serialization
  • clear request and response contracts
  • automatic API documentation support

They act as the contract between your API and the outside world.

core — Infrastructure Components

The core module usually contains shared infrastructure components such as:

  • configuration settings
  • security utilities
  • logging setup
  • application constants
  • global exception handling helpers

This layer grows slowly but becomes essential as the system matures.

dependencies — Reusable FastAPI Dependencies

Dependencies contain reusable FastAPI components used across multiple endpoints.

Examples include:

  • database session providers
  • authentication guards
  • permission checks
  • current user resolvers

Use dependencies for reusable request-time behavior, but avoid hiding complex business workflows inside them.

Layer-Based vs Feature-Based FastAPI Project Structure

There is no single folder structure that fits every FastAPI project. The right structure depends on team size, product complexity, and how quickly the application is expected to grow.

Most production teams choose between three approaches:

  • Layer-based structure — code is grouped by technical responsibility.
  • Feature-based structure — code is grouped by business domain or product feature.
  • Hybrid structure — global infrastructure stays shared, while business features are organized by domain.

When layer-based structure works best

A layer-based FastAPI structure works well for small and mid-sized APIs where the number of domains is limited.

app/
 ├ api/
 ├ services/
 ├ repositories/
 ├ models/
 ├ schemas/
 └ core/

This layout is easy to understand because each folder has a clear technical responsibility.

It works well when:

  • the API has a small number of features
  • the team is small
  • business domains are not too complex
  • the project is still moving from MVP to early production

When feature-based structure works better

A feature-based FastAPI structure works better when the application has many domains, teams, or product areas.

app/
 ├ features/
 │   ├ users/
 │   │   ├ router.py
 │   │   ├ service.py
 │   │   ├ repository.py
 │   │   ├ models.py
 │   │   └ schemas.py
 │   ├ billing/
 │   └ analytics/
 ├ core/
 ├ db/
 └ main.py

This approach keeps related code close together. For example, everything related to users lives inside the users feature instead of being spread across global routers, services, repositories, models, and schemas folders.

Feature-based organization works well when:

  • the product has several business domains
  • multiple developers work on different modules
  • merge conflicts are becoming common
  • features may later evolve into separate services

Recommended hybrid structure for production teams

For many production FastAPI applications, a hybrid structure is the safest long-term option.

Keep global infrastructure in shared folders such as core, db, and shared. Organize business capabilities inside feature folders.

app/
 ├ api/
 │   └ v1/
 ├ core/
 ├ db/
 ├ features/
 │   ├ users/
 │   ├ billing/
 │   ├ reports/
 │   └ integrations/
 ├ shared/
 └ main.py

This gives the team the clarity of layered architecture and the flexibility of domain-based organization.

Production-Ready FastAPI Architecture

Once APIs grow beyond small services, most teams move toward a layered architecture.

This structure introduces clearer responsibilities across the system and forms the foundation of a scalable FastAPI backend architecture.

A common architecture includes four layers:

  1. Router Layer
  2. Service Layer
  3. Repository Layer
  4. Database Layer

Each layer plays a distinct role.

Layered FastAPI backend architecture showing request flow from router to service layer, repository layer, and database
In scalable FastAPI systems, requests typically flow through routers, service layers, repositories, and the database to maintain clean separation of concerns.

Request Flow

In most production systems, requests move through the architecture like this:

Client Request
     ↓
Router
     ↓
Service
     ↓
Repository
     ↓
Database

This flow may look simple, but it introduces an important benefit: predictability.

Developers know exactly where logic should live.

Router Layer

Routers represent the API boundary.

Example:

@router.post("/users")
def create_user(payload: UserCreate):
    return user_service.create_user(payload)

Notice what the router does not do.

It does not query the database. It does not enforce complex business rules. It does not implement workflows.

It simply delegates.

This keeps endpoints readable and easy to maintain.

Service Layer

Services implement the behavior of the application.

Example:

def create_user(data: UserCreate):
    existing = user_repository.get_by_email(data.email)

    if existing:
        raise ValueError("User already exists")

    return user_repository.create(data)

The service layer coordinates workflows.

It often handles:

  • business rules
  • cross-repository logic
  • transaction orchestration
  • integration triggers
  • domain-level validation decisions

Think of this layer as the brain of the system.

Repository Layer

Repositories isolate database operations.

Example:

def get_by_email(email: str):
    return db.query(User).filter(User.email == email).first()

This abstraction brings several advantages:

  • cleaner service logic
  • easier testing
  • simpler database migrations
  • better separation between business logic and persistence

Repositories also make it easier to update database queries without touching every router or workflow.

Database Layer

The database layer manages infrastructure such as:

  • session lifecycle
  • connection pooling
  • ORM configuration
  • migrations
  • database engine setup

Keeping these responsibilities isolated reduces complexity across the rest of the system.

Most production FastAPI systems combine a clean project layout with a well-defined deployment setup. See the FastAPI deployment guide for infrastructure considerations.

Where different code should live

  • API routes: Put them in api, routers, or feature-specific router files.
  • Business workflows: Put them in services or feature-specific service files.
  • Database queries: Put them in repositories or feature-specific repository files.
  • ORM models: Put them in models or feature-specific model files.
  • Request and response schemas: Put them in schemas or feature-specific schema files.
  • Settings and security helpers: Put them in core.
  • Database sessions: Put them in db or a dedicated database module.
  • Background jobs: Put them in workers, tasks, or feature-specific job modules.

For a serious production project, a slightly more complete structure is usually better than a minimal folder tree.

A practical FastAPI project layout for 2026 may look like this:

project/
 ├ app/
 │   ├ main.py
 │   ├ api/
 │   │   └ v1/
 │   │       ├ api.py
 │   │       └ routes/
 │   ├ core/
 │   │   ├ settings.py
 │   │   ├ security.py
 │   │   └ logging.py
 │   ├ db/
 │   │   ├ session.py
 │   │   └ base.py
 │   ├ features/
 │   │   ├ users/
 │   │   │   ├ router.py
 │   │   │   ├ service.py
 │   │   │   ├ repository.py
 │   │   │   ├ models.py
 │   │   │   └ schemas.py
 │   │   ├ billing/
 │   │   └ reports/
 │   ├ shared/
 │   └ workers/
 ├ tests/
 ├ alembic/
 ├ pyproject.toml
 ├ .env.example
 └ README.md

This layout supports API versioning, business-domain separation, testing, migrations, shared infrastructure, and background processing.

API Versioning

API versioning protects existing clients from breaking changes.

Example endpoints might look like:

/api/v1/users
/api/v2/users

This allows the API to evolve safely while older clients continue functioning.

Many experienced teams adopt versioning earlier than expected because it prevents painful migrations later.

Database and Migrations

The database setup should not be scattered across routers or services.

A common structure is:

app/
 ├ db/
 │   ├ session.py
 │   └ base.py
alembic/
 ├ versions/
 └ env.py

The db folder can manage session creation, database engine setup, and shared database configuration. The alembic directory can manage schema migrations when the project uses SQLAlchemy or SQLModel.

Testing Layer

Production systems require automated testing.

The tests directory usually mirrors the application structure:

tests/
 ├ users/
 │   ├ test_user_routes.py
 │   ├ test_user_service.py
 │   └ test_user_repository.py
 ├ billing/
 └ conftest.py

A practical testing setup often includes:

  • unit tests for service logic
  • repository tests for database behavior
  • API tests for routes
  • test fixtures for database sessions and authentication
  • async API testing with tools such as pytest and httpx

Testing ensures architecture changes do not introduce unexpected regressions.

Utilities and Shared Code

The shared or utils module should stay small.

Useful shared modules may include:

  • hashing utilities
  • token helpers
  • formatting helpers
  • shared exceptions
  • common response helpers

Avoid creating one giant helpers.py file. That file usually becomes a junk drawer. Useful for socks at home, not for production backend code.

Dependency Injection Pattern in FastAPI

One of FastAPI’s most powerful features is its dependency injection system.

Many developers initially use it only for database sessions, but it can support much more.

Dependency injection allows infrastructure components to be reused across the application.

Database Dependency Example

Example:

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

Endpoints can request this dependency.

@router.get("/users")
def get_users(db: Session = Depends(get_db)):
    return service.get_users(db)

This centralizes session management and keeps routers clean.

Authentication Dependencies

Dependencies also simplify authentication logic.

Example:

def get_current_user(token: str = Depends(oauth2_scheme)):
    return auth_service.verify_token(token)

Routes automatically receive validated user objects.

This reduces repeated authentication logic across endpoints.

Why This Pattern Matters

Dependency injection improves architecture in several ways.

  • It reduces coupling between modules.
  • It centralizes infrastructure logic.
  • It simplifies testing and mocking.
  • It keeps repeated request-time logic out of route handlers.

For teams running larger APIs, this pattern becomes extremely valuable.

Configuration and Environment Management

Production APIs typically run across multiple environments:

  • development
  • staging
  • production

Managing configuration correctly becomes essential.

Environment Variables

Configuration should be injected through environment variables or a secure runtime configuration system.

Typical examples include:

  • database URLs
  • API keys
  • secret tokens
  • service endpoints
  • third-party integration credentials

Hardcoding these values inside the codebase creates operational and security risks.

Pydantic Settings

FastAPI projects often use Pydantic settings or pydantic-settings to manage configuration.

Example:

class Settings(BaseSettings):
    database_url: str
    secret_key: str

    class Config:
        env_file = ".env"

This pattern ensures configuration is:

  • type-safe
  • environment-aware
  • centralized
  • easier to test

For local development, an .env file is usually fine. For production systems, teams often move secrets into managed services such as cloud secrets managers or deployment-level environment variables.

Common FastAPI Project Structure Mistakes

Even experienced teams sometimes introduce structural problems without realizing it.

Recognizing these patterns early can save significant refactoring later.

Database Logic in Routers

Example:

@router.get("/users")
def get_users():
    return db.query(User).all()

This tightly couples the API layer with database access.

Repositories should handle database queries.

Business Logic Inside Endpoints

Endpoints should remain thin.

Heavy logic belongs in the service layer.

When endpoints grow too large, debugging becomes difficult.

Skipping the Service Layer

Some developers connect routers directly to repositories.

This works for small systems, but larger workflows quickly become scattered across files.

The service layer provides a coordination point for complex logic.

Unstructured Utility Modules

Large helpers.py files often become catch-all locations.

Instead, organize utilities by purpose:

utils/
  hashing.py
  tokens.py
  formatting.py

This keeps the codebase easier to navigate.

Creating Too Many Abstractions Too Early

Clean architecture does not mean adding ten folders before the product has ten users.

For an MVP, a simple structure is fine. Add services, repositories, feature modules, workers, and advanced patterns when the project actually needs them.

The goal is not to impress other developers with folder names. The goal is to make the system easier to change.

Mixing Feature Logic Into Shared Modules

Shared modules should contain truly reusable logic.

If billing logic, user logic, analytics logic, and notification logic all end up inside shared, the project has simply created a new version of the messy router problem.

When should you refactor a FastAPI project structure? A good rule of thumb is to refactor architecture when routers exceed a few hundred lines or when business logic starts repeating across endpoints. These are signals that the application has outgrown its initial structure and should adopt clearer layers or feature-based organization.

If your FastAPI backend has outgrown its original structure, FastAPI development services can help with architecture review, backend refactoring, service-layer cleanup, and production-ready API design.

FastAPI Project Structure for SaaS and AI Backends

FastAPI is often used for SaaS products, AI platforms, internal tools, analytics systems, and high-performance API backends. These systems usually need more than simple CRUD endpoints.

A SaaS backend may include:

  • authentication and user management
  • billing and subscription workflows
  • team and role permissions
  • admin tools
  • reporting and analytics
  • third-party integrations

An AI backend may include:

  • LLM orchestration
  • background processing
  • file parsing
  • vector search or retrieval workflows
  • report generation
  • external API calls

These workflows should not be squeezed into routers. They usually need services, workers, integrations, repositories, and clean boundaries between product logic and infrastructure logic.

For example, the Genhance.ai case study shows how an AI product needs structured product flows, source tracking, report generation, and user-facing workflows. In platforms like that, backend structure matters because the system needs to evolve without every new feature turning into a risky rewrite.

Scaling FastAPI Architecture

As products grow, architecture evolves.

New requirements often appear:

  • background processing
  • message queues
  • event-driven workflows
  • distributed services
  • observability and structured logging

Background Workers

Certain tasks should not block API responses.

Examples include:

  • sending emails
  • processing files
  • generating reports
  • running AI workflows
  • syncing data with external systems

These tasks are usually moved into background workers or task queues.

A practical structure may look like this:

app/
 ├ workers/
 │   ├ email_worker.py
 │   ├ report_worker.py
 │   └ ai_worker.py
 ├ features/
 └ core/

Simple tasks may use FastAPI background tasks. Heavier or business-critical workflows often need dedicated workers, queues, retries, and monitoring.

Event-Driven Systems

Larger platforms often use event-driven patterns.

Example scenario:

A user registers and multiple systems respond.

Possible actions include:

  • sending welcome emails
  • creating analytics records
  • notifying internal systems
  • starting onboarding workflows

Events allow systems to grow without tightly coupling services.

FastAPI is also frequently used to power AI-driven workflows. See how developers build AI pipelines in this guide on building AI workflows with FastAPI and LangGraph.

Microservices Evolution

As platforms mature, domains may split into independent services.

Examples include:

  • authentication service
  • billing service
  • analytics service
  • notification service

When the original FastAPI architecture is modular, this transition becomes much smoother.

Teams running FastAPI at scale often encounter concurrency and performance challenges, discussed in FastAPI production issues under load.

FastAPI Project Structure Checklist

Use this checklist before calling a FastAPI project production-ready.

  • Keep routers thin and focused on HTTP concerns.
  • Move business workflows into services.
  • Keep database queries inside repositories or data-access modules.
  • Separate request and response schemas from ORM models.
  • Keep main.py small and predictable.
  • Use a clear configuration module for settings and secrets.
  • Add tests early and mirror the app structure where practical.
  • Use migrations for database schema changes.
  • Keep shared utilities small and purposeful.
  • Move long-running tasks into workers or queues.
  • Use feature-based organization when the product has many domains.
  • Avoid overengineering small MVPs before the complexity exists.

If you are building production FastAPI systems, start with the complete FastAPI Guide to explore setup, deployment, scaling, and related backend architecture topics.

Conclusion

FastAPI makes it easy to start building APIs quickly.

But building scalable backend systems requires thoughtful architecture.

A strong FastAPI project structure separates responsibilities into routers, services, repositories, schemas, configuration, tests, and infrastructure layers. This structure keeps the system maintainable even as complexity increases.

For smaller APIs, a layer-based structure may be enough. For larger SaaS products, AI platforms, and multi-domain systems, a feature-based or hybrid architecture is usually easier to maintain.

Many CTOs eventually share a similar lesson: the earlier architecture discipline is introduced, the easier the system becomes to evolve.

If you are building a production FastAPI platform, the goal is not to create the fanciest folder tree. The goal is to make the backend easier to change, test, scale, and hand over to future developers.

Frequently Asked Questions

What is the best FastAPI project structure for production apps?

A production FastAPI project should separate API routes, business logic, database access, schemas, configuration, and tests. A common structure includes api, services, repositories, models, schemas, core, and tests.

How should I organize a FastAPI application structure?

Organize a FastAPI app around clear responsibilities. Keep routing inside api or routers, business workflows inside services, database queries inside repositories, shared configuration inside core, and validation models inside schemas.

Should FastAPI projects use layer-based or feature-based structure?

Layer-based structure works well for small and mid-sized APIs. Feature-based structure works better for larger products where domains like users, billing, analytics, and integrations need their own routers, services, repositories, and schemas.

What should go inside main.py in a FastAPI project?

The main.py file should initialize the FastAPI app, register routers, attach middleware, and configure startup or lifespan events. It should not contain business logic, database queries, or large endpoint implementations.

Where should business logic live in FastAPI?

Business logic should live in the service layer, not inside routers. Routers should handle HTTP requests and responses, while services coordinate workflows, validation decisions, integrations, and repository calls.

What is the repository pattern in FastAPI?

The repository pattern keeps database queries separate from business logic. Services call repositories to read or write data, which makes the codebase easier to test, refactor, and maintain as the application grows.

Where should tests and migrations live in a FastAPI project?

Tests usually live in a top-level tests directory that mirrors the application structure. Database migrations typically live in an alembic directory when using SQLAlchemy or SQLModel with Alembic.

How should large FastAPI projects handle background jobs?

Large FastAPI projects should keep long-running work outside request handlers. Simple jobs can use background tasks, while heavier workflows should use workers, queues, or task systems such as Celery, RQ, or Arq.

Share:
Shivam Sharma
Shivam Sharma

About the Author

With over 13 years of experience in software development, I am the Founder, Director, and CTO of Zestminds, an IT agency specializing in custom software solutions, AI innovation, and digital transformation. I lead a team of skilled engineers, helping businesses streamline processes, optimize performance, and achieve growth through scalable web and mobile applications, AI integration, and automation.

Schedule a Call

Before You Scale Further, Review the Architecture.

Let’s evaluate where your system stands — and where it may break under growth.

Schedule an Architecture Review 30-minute technical discussion. No obligation.