pyRPC
← Back to Blog

Router.merge: how pyRPC handles namespaces

·8 min read

When your project grows past ten procedures, a single flat router becomes hard to navigate. pyRPC's Router.merge() lets you split procedures into separate modules and combine them at the top level.

The basic pattern

# users.py
from pyrpc_core import Router

users = Router()

@users.rpc
def get_user(user_id: int) -> dict: ...

@users.rpc
def update_user(user_id: int, name: str) -> dict: ...

# orders.py
from pyrpc_core import Router

orders = Router()

@orders.rpc
def get_order(order_id: int) -> dict: ...

# app.py
from pyrpc_core import Router
from users import users
from orders import orders

router = Router()
router.merge(users)
router.merge(orders)

Each module gets its own Router. The main app merges them. The framework adapter sees one flat namespace of procedures.

With prefixes

merge() accepts an optional prefix parameter. Procedures become prefix.procedure_name:

router.merge(users, prefix="users")
router.merge(orders, prefix="orders")

On the TypeScript side, you get api.users.get_user.useQuery() and api.orders.get_order.useQuery(). Without prefixes, it is just api.get_user.useQuery().

Why this matters

Larger projects need separation. One team owns users, another owns orders. Each team writes their own Router. The main app merges them. No circular imports, no shared state, no framework-specific routing.

This is the same pattern tRPC uses with nested routers, but pyRPC keeps it simpler: flat merge, optional prefix, one level. If you need deeper nesting, just merge a merged router.

Procedures docs · Adapters deep dive