Skip to main content
RapidDev - Software Development Agency
v0-integrationsNext.js API Route

How to Integrate TYPO3 with V0

Connect V0 by Vercel to TYPO3 by enabling the EXT:headless extension in your TYPO3 installation to expose a JSON content API, then using a Next.js API route to fetch and serve that content to your V0-generated React frontend. Store your TYPO3 API base URL as a server-only environment variable in Vercel.

What you'll learn

  • How TYPO3's EXT:headless extension exposes content as a JSON API
  • How to create a Next.js API route that proxies TYPO3 headless API requests
  • How to store your TYPO3 API URL securely in Vercel environment variables
  • How to have V0 generate content display components that fetch from your TYPO3 proxy route
  • How to handle TYPO3's structured content response format in a React component
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate17 min read45 minutesCMSMarch 2026RapidDev Engineering Team
TL;DR

Connect V0 by Vercel to TYPO3 by enabling the EXT:headless extension in your TYPO3 installation to expose a JSON content API, then using a Next.js API route to fetch and serve that content to your V0-generated React frontend. Store your TYPO3 API base URL as a server-only environment variable in Vercel.

Using TYPO3 as a Headless CMS for V0 Next.js Frontends

TYPO3 powers many enterprise and government websites across Europe, with robust content modeling, multilingual support, and workflow management built in. For organizations that already manage content in TYPO3, rebuilding in a new CMS is not practical — the content, taxonomy, and editorial workflows are too deeply established. Instead, the headless approach lets you keep TYPO3 as the content backend while building a modern React frontend using V0 by Vercel.

The EXT:headless extension (maintained by the Macopedia team and widely used in the TYPO3 community) converts TYPO3's page tree and content elements into a REST API that returns structured JSON. Each TYPO3 page becomes accessible at a URL like `https://your-typo3.com/?type=834` or via the dedicated API path the extension provides. The response includes page metadata, content elements, and any custom fields you have configured on your content types.

V0 generates the React components and page layouts that consume this JSON, while a Next.js API route acts as a secure proxy between the frontend and TYPO3. This proxy pattern is important because it keeps your TYPO3 internal URL hidden from browser requests, allows you to add authentication headers without exposing API tokens to the client, and enables response caching at the Next.js layer for improved performance.

Integration method

Next.js API Route

TYPO3's EXT:headless extension transforms your TYPO3 installation into a headless CMS by exposing page content as structured JSON via REST API endpoints. V0 generates the Next.js frontend components, and a Next.js API route fetches content from TYPO3's headless API, acting as a proxy that keeps your TYPO3 base URL server-side. React components fetch from the proxy route and render the content.

Prerequisites

  • A TYPO3 installation (version 11 LTS or 12 LTS recommended) with administrator access
  • EXT:headless extension installed in your TYPO3 instance (available via TER or Composer)
  • A V0 by Vercel account at v0.dev with GitHub connected
  • The base URL of your TYPO3 installation accessible over HTTPS
  • Basic familiarity with Next.js API routes and JSON data handling

Step-by-step guide

1

Install and Configure EXT:headless in TYPO3

Before you can fetch TYPO3 content from a Next.js frontend, you need to enable TYPO3's headless API capability. The EXT:headless extension transforms TYPO3 from a traditional server-rendered CMS into a headless API provider that outputs structured JSON instead of HTML. Install EXT:headless via TYPO3's Extension Manager or via Composer. In the TYPO3 backend, navigate to Admin Tools → Extension Manager → Get Extensions and search for 'headless'. Click Install. Alternatively, if your TYPO3 is Composer-managed, run `composer require friendsoftypo3/headless` in your TYPO3 root directory. After installation, you need to configure EXT:headless in your TYPO3 TypoScript template. Navigate to Web → Template in the TYPO3 backend, select your root page, and open the TypoScript editor. Add the static include for EXT:headless: go to Edit the whole template record → Includes → Include static (from extensions) and add 'Headless (headless)'. To test that the headless API is working, append `?type=834` to your TYPO3 site URL in the browser. If EXT:headless is correctly configured, you will see a JSON response instead of your normal HTML website. The response structure includes a `meta` object with page metadata, a `content` array with the page's content elements, and a `navigation` array with the site's page tree. This JSON endpoint is what your Next.js API route will consume. Note the base URL of your TYPO3 installation — you will need it in the next step when configuring the Vercel environment variable.

Pro tip: TYPO3's headless API returns the page type 834 by default for EXT:headless. Your TYPO3 administrator can confirm the correct type number and any API authentication requirements for your specific installation.

Expected result: Visiting your TYPO3 URL with ?type=834 returns a JSON response with page content data instead of rendered HTML. The JSON includes meta, content, and navigation sections.

2

Generate the Content Display UI in V0

With TYPO3's headless API confirmed working, switch to V0 to generate the React components that will display this content. You are building the visual layer — V0 does not need to know anything about TYPO3 at this stage. Describe the page layout and content structure you want based on the types of content your TYPO3 site manages. In the V0 chat panel, write a prompt describing the content display component. For a content page, you typically need: a page title and metadata area, a body content renderer that handles rich text, optional image sections, and a navigation sidebar or breadcrumb. V0 will generate a React component with appropriate props. After V0 generates the component, review the preview. The key thing to check is whether the component structure maps well to what TYPO3's headless API will return. TYPO3 content elements are structured as objects with `type`, `id`, `content`, and custom field properties. Your React component will need to iterate over the content array and render each element based on its type. If the layout looks good but the data structure does not quite match, you can either refine the V0 prompt to match TYPO3's output format, or plan to add a data transformation step in your API route that reshapes TYPO3's response into the props format your component expects. The latter approach is often cleaner. Once satisfied with the V0 preview, push the project to GitHub using V0's Git panel.

V0 Prompt

Create a content page template with a breadcrumb trail at the top, a full-width hero with page title and subtitle, a main content area that accepts a blocks array and renders each block as either a text block, an image with caption, or a two-column layout. Add a sidebar with a table of contents that links to headings in the content. Use clean typography with proper heading hierarchy.

Paste this in V0 chat

Pro tip: Ask V0 to keep the component props generic (accepting a 'content' array of typed blocks) rather than TYPO3-specific — this makes the component reusable and easier to populate from your API route transformation step.

Expected result: A Next.js project on GitHub with a content page component that accepts structured content props and renders page layouts. The component is ready to receive real data from the TYPO3 headless API.

3

Create a Next.js API Route to Proxy TYPO3 Content

Now create the Next.js API route that acts as a proxy between your React frontend and the TYPO3 headless API. This route fetches content from TYPO3, transforms the response into a clean JSON format your React component can use, and returns it. Running this on the server (in an API route) means your TYPO3 base URL and any authentication headers are never exposed to the browser. Create the file `app/api/typo3/route.ts`. The route accepts a `pageId` query parameter (or a `slug` parameter if your TYPO3 uses slug-based routing), constructs the TYPO3 API URL using the base URL from your environment variable, fetches the content, transforms it, and returns the result. The transformation step is important because TYPO3's EXT:headless response is quite verbose — it includes rendering hints, FlexForm data, and TYPO3-specific metadata that your React component does not need. Stripping this down to only the fields your component uses reduces response size and keeps the component decoupled from TYPO3's internal structure. For content elements, TYPO3 headless returns each content element as an object with a `type` field (like `text`, `textpic`, `image`, `bullets`) and element-specific content fields. Your transformation maps these to the block types your React component understands. This is also where you handle differences between TYPO3 versions — the transformation layer absorbs TYPO3 API changes without breaking your frontend.

app/api/typo3/route.ts
1// app/api/typo3/route.ts
2import { NextRequest, NextResponse } from 'next/server';
3
4const TYPO3_API_URL = process.env.TYPO3_API_URL;
5// e.g., "https://your-typo3-site.com"
6
7interface Typo3ContentElement {
8 type: string;
9 id: number;
10 content: {
11 header?: string;
12 bodytext?: string;
13 media?: Array<{ publicUrl: string; properties: { title: string; alternative: string } }>;
14 };
15}
16
17interface Typo3HeadlessResponse {
18 meta: {
19 title: string;
20 subtitle: string;
21 description: string;
22 breadcrumb: Array<{ title: string; link: string }>;
23 };
24 content: {
25 colPos0: Typo3ContentElement[];
26 [key: string]: Typo3ContentElement[];
27 };
28 navigation: Array<{ title: string; link: string; children?: unknown[] }>;
29}
30
31function transformContent(elements: Typo3ContentElement[]) {
32 return elements.map((el) => ({
33 id: el.id,
34 type: el.type,
35 header: el.content?.header ?? '',
36 body: el.content?.bodytext ?? '',
37 images: (el.content?.media ?? []).map((m) => ({
38 url: m.publicUrl,
39 alt: m.properties?.alternative ?? '',
40 caption: m.properties?.title ?? '',
41 })),
42 }));
43}
44
45export async function GET(request: NextRequest) {
46 const { searchParams } = new URL(request.url);
47 const pageId = searchParams.get('pageId') ?? '1';
48
49 if (!TYPO3_API_URL) {
50 return NextResponse.json(
51 { error: 'TYPO3_API_URL environment variable is not set' },
52 { status: 500 }
53 );
54 }
55
56 try {
57 const typo3Url = `${TYPO3_API_URL}/?type=834&id=${pageId}`;
58
59 const response = await fetch(typo3Url, {
60 headers: {
61 Accept: 'application/json',
62 // Add Authorization header if your TYPO3 requires API auth:
63 // Authorization: `Bearer ${process.env.TYPO3_API_TOKEN}`,
64 },
65 // Cache TYPO3 responses for 60 seconds at the Next.js layer
66 next: { revalidate: 60 },
67 });
68
69 if (!response.ok) {
70 throw new Error(`TYPO3 API returned ${response.status}`);
71 }
72
73 const data: Typo3HeadlessResponse = await response.json();
74
75 // Transform TYPO3's response into a clean format
76 const transformed = {
77 meta: {
78 title: data.meta?.title ?? '',
79 subtitle: data.meta?.subtitle ?? '',
80 description: data.meta?.description ?? '',
81 breadcrumb: data.meta?.breadcrumb ?? [],
82 },
83 blocks: transformContent(data.content?.colPos0 ?? []),
84 navigation: data.navigation ?? [],
85 };
86
87 return NextResponse.json(transformed);
88 } catch (error) {
89 console.error('TYPO3 API error:', error);
90 return NextResponse.json(
91 { error: 'Failed to fetch content from TYPO3' },
92 { status: 500 }
93 );
94 }
95}

Pro tip: Use Next.js fetch caching (`next: { revalidate: 60 }`) in your TYPO3 API fetch call to cache responses for 60 seconds — this dramatically reduces load on your TYPO3 server for high-traffic pages.

Expected result: The API route at /api/typo3?pageId=1 returns a clean JSON object with meta, blocks, and navigation. The response is the transformed version of TYPO3's verbose headless API output.

4

Add TYPO3_API_URL to Vercel Environment Variables

Your TYPO3 installation's base URL must be stored as a server-only environment variable in Vercel Dashboard. This prevents the TYPO3 URL from being exposed in the browser's network requests, which is especially important if your TYPO3 is on a private network or has authentication requirements. Go to your Vercel Dashboard at vercel.com. Select your project and navigate to Settings → Environment Variables. Click Add New. Add **TYPO3_API_URL** with the value being the base URL of your TYPO3 installation, without a trailing slash. For example: `https://cms.yourcompany.com`. Make sure this is the publicly accessible URL that your Vercel serverless functions can reach over the internet. If your TYPO3 is on a private corporate network, you will need to either expose it via a secure tunnel or use Vercel's edge network features to route traffic. If your TYPO3 requires API token authentication (for private content), also add **TYPO3_API_TOKEN** with the bearer token value. In your API route, uncomment the Authorization header line in the fetch options. Set the environment scope for both variables to at least 'Production'. For staging/development, you can point to a TYPO3 staging instance by adding a separate value for the 'Preview' environment scope. For local development, create a `.env.local` file in the project root with `TYPO3_API_URL=https://your-typo3-staging.com`. Make sure `.env.local` is in your `.gitignore` file — your Next.js project from V0 should already have this configured correctly.

.env.local
1# .env.local (never commit to git)
2TYPO3_API_URL=https://your-typo3-site.com
3# Optional: only if your TYPO3 requires API authentication
4TYPO3_API_TOKEN=your_api_bearer_token_here

Pro tip: Use separate TYPO3 instances for preview vs production in Vercel: set TYPO3_API_URL to your staging TYPO3 for the Preview environment scope and to production TYPO3 for the Production scope.

Expected result: TYPO3_API_URL is saved in Vercel Dashboard under Settings → Environment Variables. The variable is scoped to Production (and Preview if needed) and does not have a NEXT_PUBLIC_ prefix.

5

Connect the V0 Component to the TYPO3 API Route and Deploy

The final step is connecting your V0-generated React component to the TYPO3 API route. Clone your GitHub repository locally (or use V0's Dev Mode), and update the content page component to fetch from `/api/typo3?pageId=1` and pass the response data as props to your content renderer. For a page-based site, you will typically create a dynamic Next.js page at `app/[slug]/page.tsx` that extracts the slug from the URL, maps it to a TYPO3 page ID (either from a hardcoded map or by fetching TYPO3's navigation tree), and fetches the content. For a simpler setup, start with a static page ID to verify the connection works before adding dynamic routing. Update the component to use React's `fetch` in a Server Component (or `useEffect` in a Client Component) to call your API route. Map the `blocks` array from the API response to the block renderer in your component. Test locally by running `npm run dev` — visiting `localhost:3000` should show your TYPO3 content rendered through the React component. Once you have confirmed the local integration works correctly, commit and push to GitHub. Vercel will deploy automatically. Check the Vercel deployment logs for any errors — common issues at this stage are network connectivity to TYPO3 (check if your TYPO3 server allows connections from Vercel's IP ranges) and JSON parsing errors if TYPO3's API response format differs from what your transformation expects. For complex TYPO3 setups with custom content elements or the EXT:news extension, RapidDev's team can help map TYPO3's content element structure to React component props for a complete headless implementation.

V0 Prompt

Update the content page to fetch from /api/typo3?pageId=1 on server load. Pass the meta object as page metadata (title, description for SEO) and the blocks array to the content renderer. Each block with type 'text' should render as a rich text section, type 'textpic' should render as text with an image, and type 'image' should render as a full-width image with caption.

Paste this in V0 chat

app/page.tsx
1// app/page.tsx (simplified Server Component example)
2import { ContentPage } from './components/content-page';
3
4async function getTypo3Content(pageId: string) {
5 // In production, use your full Vercel URL
6 const baseUrl = process.env.NEXT_PUBLIC_BASE_URL ?? 'http://localhost:3000';
7 const res = await fetch(`${baseUrl}/api/typo3?pageId=${pageId}`, {
8 next: { revalidate: 60 },
9 });
10 if (!res.ok) throw new Error('Failed to fetch TYPO3 content');
11 return res.json();
12}
13
14export default async function Home() {
15 const content = await getTypo3Content('1');
16
17 return (
18 <ContentPage
19 title={content.meta.title}
20 subtitle={content.meta.subtitle}
21 breadcrumb={content.meta.breadcrumb}
22 blocks={content.blocks}
23 navigation={content.navigation}
24 />
25 );
26}

Pro tip: Set NEXT_PUBLIC_BASE_URL in your Vercel environment variables to your production domain (e.g., https://yourapp.vercel.app) so server-to-server fetch calls in Server Components work correctly in production.

Expected result: Your Next.js app deployed on Vercel renders TYPO3 content in the V0-generated React components. The page title, breadcrumb, and content blocks are populated from real TYPO3 data. Deployment logs show no errors.

Common use cases

Multilingual Marketing Site

A European enterprise manages their marketing website in TYPO3 with content in 8 languages. V0 generates a Next.js page template that reads language-specific content from TYPO3's headless API, with the language code passed as a query parameter. The Next.js API route handles language resolution and returns the correct TYPO3 content.

V0 Prompt

Create a marketing page template with a hero section, a two-column text and image section, a feature list, and a contact CTA. The component should accept a pageData prop containing title, body, image, and features array and render them with clean typography and Tailwind styling.

Copy this prompt to try it in V0

News and Article Archive

A publisher stores all their articles in TYPO3's News extension (EXT:news). V0 generates a news listing page with article cards and a detail page template. The Next.js API route fetches news records from TYPO3's headless API and returns them with pagination support.

V0 Prompt

Build a news listing page with a grid of article cards showing thumbnail image, category badge, headline, publication date, and a read more link. Include pagination controls at the bottom. The component should accept an articles array prop and totalPages number.

Copy this prompt to try it in V0

Product Documentation Portal

A software company uses TYPO3 to manage technical documentation with versioned pages, structured content elements, and file attachments. V0 generates a documentation portal UI with a sidebar navigation tree and a content area that renders TYPO3's structured content elements as React components.

V0 Prompt

Create a documentation layout with a collapsible sidebar showing a navigation tree on the left, and a content area on the right with a breadcrumb trail, page title, body content rendered as formatted text, and a table of contents auto-generated from headings.

Copy this prompt to try it in V0

Troubleshooting

The TYPO3 API returns HTML instead of JSON when accessing ?type=834

Cause: EXT:headless is not correctly activated, or the TypoScript static template for headless is not included on the root page. The TYPO3 installation may also have caching that is serving the cached HTML response.

Solution: In TYPO3 backend, go to Web → Template, select the root page, and verify the EXT:headless static template is included. Clear TYPO3's cache under Admin Tools → Maintenance → Flush TYPO3 and PHP Cache. If using TYPO3 12, check whether the headless extension supports your specific TYPO3 version by checking the extension's composer.json constraints.

Next.js API route returns 'Failed to fetch content from TYPO3' with a network error in Vercel logs

Cause: The Vercel serverless function cannot reach the TYPO3 host. Either the TYPO3_API_URL is incorrect, the TYPO3 server's firewall blocks Vercel's IP ranges, or the server requires authentication.

Solution: First verify the TYPO3_API_URL value in Vercel Dashboard matches the actual accessible URL. Test it by opening the URL in a browser on your local machine. If the URL works locally but not from Vercel, the issue is firewall-related — your TYPO3 server needs to allow inbound HTTP requests from Vercel's AWS IP ranges. Check your TYPO3 server's nginx/Apache access logs to confirm whether requests from Vercel are reaching the server.

Content blocks render as empty or undefined even though the TYPO3 API response contains data

Cause: TYPO3's headless API response structure can vary based on extension version and TYPO3 content element types. The transformation code in the API route may not be correctly mapping the specific content element types your TYPO3 is using.

Solution: Log the raw TYPO3 API response in your API route to inspect the actual JSON structure. Add `console.log(JSON.stringify(data, null, 2))` before the transformation step and check Vercel's function logs. Compare the actual response structure against your transformation code and update the field names accordingly.

typescript
1// Debug: log the raw TYPO3 response structure
2console.log('TYPO3 response keys:', Object.keys(data));
3console.log('Content colPos0 sample:', JSON.stringify(data.content?.colPos0?.[0], null, 2));

TYPO3 content images do not load — image URLs return 404 or CORS errors

Cause: TYPO3 headless returns image URLs as absolute paths on the TYPO3 server. If TYPO3 is on a private network or has authentication, those image URLs will not be accessible from the browser.

Solution: If TYPO3 is public, ensure the `publicUrl` field in the headless response contains the full public URL (not a relative path). If TYPO3 is on a private network, you need to proxy images through a Next.js API route or use Next.js Image component with a remote image domain config to rewrite URLs through a public CDN.

typescript
1// next.config.ts — allow TYPO3 images
2const nextConfig = {
3 images: {
4 remotePatterns: [
5 {
6 protocol: 'https',
7 hostname: 'your-typo3-domain.com',
8 pathname: '/fileadmin/**',
9 },
10 ],
11 },
12};
13export default nextConfig;

Best practices

  • Use Next.js fetch caching with `next: { revalidate: N }` in your TYPO3 API calls to reduce load on the TYPO3 server and improve page load times — TYPO3 content rarely changes in real time.
  • Create a transformation layer in your API route that maps TYPO3's verbose response to a minimal clean schema — this decouples your React components from TYPO3's internal data structure.
  • Store the TYPO3 base URL as an environment variable (never hardcoded) so you can easily switch between staging and production TYPO3 instances without code changes.
  • Use TYPO3's slug-based routing (EXT:slug) alongside headless so your Next.js pages can use human-readable URLs that match the TYPO3 page tree.
  • Add TYPO3 API errors to your Vercel function logs with enough context (page ID, response status) to debug content loading failures without exposing TYPO3 credentials.
  • Implement Incremental Static Regeneration (ISR) in Next.js to pre-render TYPO3 content pages at build time and regenerate them on demand when content changes.
  • Test your TYPO3 headless API responses in a tool like Postman or browser fetch before building the React integration — understanding the exact response shape saves significant debugging time.

Alternatives

Frequently asked questions

Which TYPO3 version is required for the headless integration?

EXT:headless supports TYPO3 11 LTS and TYPO3 12 LTS. TYPO3 10 LTS is approaching end-of-life and EXT:headless support for it may be limited. Check the headless extension's TYPO3 version constraints on its Packagist page before installing. TYPO3 13 support is in development as of early 2026.

Can I use TYPO3's preview functionality with a Next.js frontend?

Yes, but it requires additional setup. TYPO3's EXT:headless supports a preview mode that passes a preview token in the API request. In Next.js, you would implement Draft Mode (Next.js 13+) that activates when it receives the preview token from TYPO3. When an editor clicks 'Preview' in the TYPO3 backend, it would redirect to your Next.js URL with the preview token, which enables Draft Mode and fetches unpublished content from TYPO3.

How do I handle TYPO3's multilingual content in Next.js?

Pass a `L` query parameter to the TYPO3 headless API to request a specific language: `?type=834&id=1&L=1` (where L=1 is language UID 1 in TYPO3). In your Next.js API route, accept a `lang` query parameter from the frontend, map it to the correct TYPO3 language UID, and include it in the TYPO3 API request. For routing, use Next.js's internationalization (i18n) config to serve different language routes.

Does TYPO3 headless support TYPO3's page access restrictions and login?

EXT:headless can return restricted content if you pass a valid TYPO3 frontend user session or use the extension's JWT-based authentication. However, implementing TYPO3 frontend user authentication in a headless context is complex and requires careful session management. For most use cases, only public TYPO3 pages are served via the headless API to the Next.js frontend.

Can V0 generate the TYPO3 content renderer component automatically?

V0 can generate a generic content block renderer if you provide it with the data structure your API route returns. Share a sample API response in your V0 prompt and ask it to 'build a content renderer that handles these block types.' V0 will generate a switch-case based renderer component. You may need to refine it for TYPO3-specific content types like accordions, tabs, and custom plugins.

What is the difference between TYPO3 headless API type 834 and the REST API endpoint?

Type 834 is the classic EXT:headless approach — it uses TYPO3's eID mechanism to return the current page's content as JSON. Some versions of EXT:headless also provide dedicated REST API endpoints under a path like `/api/pages/`. The type 834 approach is the most widely documented and compatible. Check your specific EXT:headless version's documentation to confirm which endpoint format is active.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.