Data fetching
Pages can be async functions. The framework awaits them before rendering, which means you can await data directly in your components — no useEffect or data-fetching library required.
Fetching in a page
app/blog/page.tsx
async function getPosts() {
const res = await fetch("https://api.example.com/posts");
return res.json();
}
export default async function BlogPage() {
const posts = await getPosts();
return (
<ul>
{posts.map((p) => <li key={p.id}>{p.title}</li>)}
</ul>
);
}Fetching in a layout
Layouts can also be async. The data is fetched once and shared across all child pages.
Loading UI
For a non-blocking experience, combine loading.tsx with Suspense boundaries:
app/dashboard/page.tsx
import { Suspense } from "react";
export default function DashboardPage() {
return (
<Suspense fallback={<p>Loading…</p>}>
<RecentActivity />
</Suspense>
);
}
async function RecentActivity() {
const data = await fetch("https://api.example.com/activity").then((r) => r.json());
return <ul>{data.map(...)}</ul>;
}Route handlers (API routes)
For pure data endpoints, create a route.ts file. Export functions named after HTTP methods:
app/api/posts/route.ts
import type { RouteHandler } from "swift-rust/router";
export const GET: RouteHandler = async ({ request }) => {
const posts = await db.posts.findMany();
return Response.json(posts);
};
export const POST: RouteHandler = async ({ request }) => {
const body = await request.json();
const post = await db.posts.create(body);
return Response.json(post, { status: 201 });
};Next steps
Continue to Styling.