Multi-file projects
Real services have models, business logic, database adapters — all in separate files. fastgrpc supports this without any configuration.
Example layout
my_service/
├── main.py # @service classes (the gRPC surface)
├── business.py # business logic (knows nothing about gRPC)
├── models.py # dataclasses (imported by both)
└── db.py # database adapter
models.py:
from dataclasses import dataclass
@dataclass
class Address:
street: str
city: str
@dataclass
class User:
id: int
name: str
address: Address
business.py:
from models import User, Address
def find_user(user_id: int) -> User | None:
# ... query db, build User dataclass ...
return User(id=user_id, name="Ashesh",
address=Address(street="MG Road", city="Bangalore"))
main.py:
from business import find_user
from models import User
from fastgrpc import rpc, service
from fastgrpc.exceptions import NotFound
@service
class UserService:
@rpc
async def get_user(self, user_id: int) -> User:
user = find_user(user_id)
if user is None:
raise NotFound(f"user {user_id} not found")
return user
Run it:
How the import resolution works
When you run fastgrpc dev main.py, the framework:
- Resolves
main.pyto its absolute path. - Adds the parent directory (
my_service/) tosys.path. - Imports
main.pyas a top-level module.
That's why sibling imports like from business import find_user work — business.py lives next to main.py, and the parent directory is now on sys.path.
Hot reload follows imports
Edit business.py or models.py and the server reloads with your changes — same as editing main.py itself. See the Watch mode guide for the details on why this requires an explicit sys.modules purge.
Multiple services in one file
You can decorate as many classes as you want; they all become separate gRPC services on the same server:
@service
class UserService:
@rpc
async def get_user(self, user_id: int) -> User: ...
@service
class OrderService:
@rpc
async def get_order(self, order_id: str) -> Order: ...
$ grpcurl -plaintext 127.0.0.1:50051 list
fastgrpc.OrderService
fastgrpc.UserService
grpc.reflection.v1alpha.ServerReflection
Multiple services across files
You can also split services across files; just import them into your entry-point so the decorators run:
# main.py
from user_service import UserService # noqa: F401 — import for side effects
from order_service import OrderService # noqa: F401
The @service decorators register both classes regardless of where they're defined.
Service name collisions
If two @service classes happen to have the same __name__ (e.g. both files define class UserService:), fastgrpc fails fast with an error that names both modules:
ValidationError: duplicate service class name(s) detected:
'UserService' defined in: app.users:UserService, app.admin:UserService
Service class names must be unique across all files.
Rename one of them.