Skip to main content
RapidDev - Software Development Agency
bolt-ai-integrationsBolt Chat + API Route

How to Integrate Bolt.new with TYPO3

Integrate TYPO3 with Bolt.new by installing the TYPO3 Headless extension on your self-hosted TYPO3 instance, which exposes a JSON API for pages and content elements. Build a Next.js API route in Bolt to proxy requests, fetch pages and content trees, and render them in React. TYPO3 excels at enterprise multi-site and multi-language setups popular in German-speaking countries.

What you'll learn

  • How to install and configure the TYPO3 Headless extension to expose a JSON API
  • How to build a Next.js API route in Bolt.new that proxies TYPO3 content requests
  • How to handle TYPO3's multi-language content structure in React
  • How to fetch page trees and content elements using the TYPO3 Headless API
  • How to deploy your Bolt.new TYPO3 frontend to Netlify with proper environment variables
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate17 min read30 minutesCMSApril 2026RapidDev Engineering Team
TL;DR

Integrate TYPO3 with Bolt.new by installing the TYPO3 Headless extension on your self-hosted TYPO3 instance, which exposes a JSON API for pages and content elements. Build a Next.js API route in Bolt to proxy requests, fetch pages and content trees, and render them in React. TYPO3 excels at enterprise multi-site and multi-language setups popular in German-speaking countries.

Build a Headless TYPO3 Frontend with Bolt.new

TYPO3 is a battle-tested enterprise CMS with over two decades of development, particularly dominant in German-speaking markets where it powers government portals, universities, and large corporate websites. Its strength lies in granular access control, robust multi-site management, and sophisticated multi-language workflows — capabilities that go well beyond what most simpler CMSs offer. Bolt.new is an excellent tool for building a modern React frontend on top of an existing TYPO3 installation, letting content editors keep the familiar TYPO3 backend while the frontend gains full design freedom and performance benefits.

Out of the box, TYPO3 does not expose a public JSON API. You need to install the TYPO3 Headless extension (EXT:headless), a free, actively-maintained Composer package that transforms TYPO3 into a full headless CMS. Once installed, TYPO3 exposes structured JSON responses for pages, content elements, menus, and custom records at configurable REST-style endpoints. The extension handles TYPO3's complex content structure — including content columns, flexible content elements, and language overlays — and returns clean, predictable JSON that is straightforward to consume in React.

For organizations without an existing TYPO3 installation, note that TYPO3 requires a PHP and MySQL server environment — you cannot install it through Bolt.new itself. If you are starting a new project without an existing CMS, consider WordPress or Ghost as simpler headless CMS alternatives. This guide assumes you have a running TYPO3 instance (version 11 LTS or 12 LTS recommended) where you can install Composer packages and configure site settings.

Integration method

Bolt Chat + API Route

TYPO3 requires the free TYPO3 Headless extension to expose a JSON API for pages and content elements. Once the extension is installed and configured, Bolt.new connects via a Next.js API route that proxies requests to your TYPO3 instance, keeping any authentication tokens server-side. The API route fetches pages, content trees, and individual content elements, which React components consume to render the frontend independently of TYPO3's own templating engine.

Prerequisites

  • A running TYPO3 instance (version 11 LTS or 12 LTS) with Composer-based installation and server access to install extensions
  • The TYPO3 Headless extension (EXT:headless) installed via Composer: composer require friendsoftypo3/headless
  • Your TYPO3 site URL and the base URL of the configured Headless API endpoint
  • Optional: A TYPO3 API token if you have configured frontend user access restrictions on any pages
  • A Bolt.new account with a new Next.js project open

Step-by-step guide

1

Install TYPO3 Headless Extension and Configure the JSON API

TYPO3 does not include a headless JSON API out of the box — you must install the EXT:headless extension developed by TYPO3 agency Macopedia and maintained by the Friends of TYPO3 organization. On your TYPO3 server, run the Composer command to install the extension: composer require friendsoftypo3/headless. After installation, activate the extension in the TYPO3 backend under Admin Tools → Extensions. The extension adds a new site configuration option called 'headless' that you need to enable in your site configuration file (typically located at config/sites/your-site/config.yaml). Add headless: true under the root site configuration block. Once activated, TYPO3 Headless responds to requests with a type parameter of 834 — for example, https://your-typo3.com/?type=834 returns the homepage content as JSON. You can verify the API is working by opening that URL in your browser and checking that it returns a JSON object with page and content data rather than HTML. The extension also respects TYPO3's existing page access settings and caching configuration — cached responses are automatically invalidated when editors publish new content in the TYPO3 backend. For TYPO3 12+, the modern PSR-15 middleware approach is the default and provides faster response times than the legacy type-parameter approach used in older versions.

config/sites/main/config.yaml
1# config/sites/main/config.yaml add headless: true
2base: 'https://your-typo3.com/'
3baseVariants: []
4errorHandling: []
5headless: true
6languages:
7 -
8 base: /
9 enabled: true
10 languageId: 0
11 locale: en_US.UTF-8
12 title: English
13rootPageId: 1
14websiteTitle: 'My TYPO3 Site'
15
16# Verify the API works by opening in browser:
17# https://your-typo3.com/?type=834
18# Expected: JSON object with page title, content array, metadata

Pro tip: If you are using TYPO3 12+, also install the headless_news or headless_blog extensions if your site uses EXT:news or EXT:blog — these companion packages add JSON support for those common TYPO3 content extensions.

Expected result: Visiting https://your-typo3.com/?type=834 in a browser returns a JSON object containing page data and content elements instead of rendered HTML.

2

Set Up Environment Variables and Prompt Bolt to Generate the API Route

With TYPO3 Headless configured and responding with JSON, the next step is building the server-side proxy in your Bolt.new project. A proxy API route is essential for two reasons: first, TYPO3 installations often do not include CORS headers for browser requests originating from a different domain, which would cause direct client-side fetch calls to fail in Bolt's preview; second, any authentication tokens or credentials for accessing restricted content must remain server-side and never be exposed in client-side code. In your Bolt.new project, create a .env file at the project root. Add TYPO3_API_URL set to your TYPO3 site's base URL (for example, https://your-typo3.com). If your TYPO3 site requires an API token for accessing certain pages or frontend user groups, also add TYPO3_API_TOKEN. Keep in mind that Bolt's WebContainer environment means that all API calls go outbound from the browser-based Node.js runtime — outbound HTTP calls to your TYPO3 server work correctly in the Bolt preview, so you can test and iterate on the integration before deploying. Once you have the .env file ready, use the Bolt chat prompt below to generate the main TYPO3 API route. After Bolt generates the code, review that it reads TYPO3_API_URL from process.env without a NEXT_PUBLIC_ prefix (keeping it server-side only) and that the request includes the type=834 parameter required by the TYPO3 Headless extension.

Bolt.new Prompt

Create a TYPO3 headless CMS integration in this Next.js project. Build an API route at app/api/typo3/page/route.ts that fetches a page from TYPO3 Headless API. Read TYPO3_API_URL from process.env. Accept a 'slug' query parameter (default to '/'). Construct the TYPO3 Headless URL as TYPO3_API_URL + '?type=834&tx_headless_page[action]=page&tx_headless_page[controller]=Page&tx_headless_page[slug]=' + encodeURIComponent(slug). If TYPO3_API_TOKEN env var exists, add an Authorization Bearer header. Handle fetch errors gracefully and return a 500 with the error message. Parse and return the full TYPO3 JSON response including page title, meta, breadcrumbs, and content array.

Paste this in Bolt.new chat

app/api/typo3/page/route.ts
1// app/api/typo3/page/route.ts
2import { NextRequest, NextResponse } from 'next/server';
3
4export async function GET(request: NextRequest) {
5 const apiUrl = process.env.TYPO3_API_URL;
6 if (!apiUrl) {
7 return NextResponse.json(
8 { error: 'TYPO3_API_URL is not configured' },
9 { status: 500 }
10 );
11 }
12
13 const { searchParams } = new URL(request.url);
14 const slug = searchParams.get('slug') || '/';
15
16 const typo3Url = new URL(apiUrl);
17 typo3Url.searchParams.set('type', '834');
18 typo3Url.searchParams.set('tx_headless_page[action]', 'page');
19 typo3Url.searchParams.set('tx_headless_page[controller]', 'Page');
20 typo3Url.searchParams.set('tx_headless_page[slug]', slug);
21
22 const headers: Record<string, string> = {
23 'Accept': 'application/json',
24 };
25
26 if (process.env.TYPO3_API_TOKEN) {
27 headers['Authorization'] = `Bearer ${process.env.TYPO3_API_TOKEN}`;
28 }
29
30 try {
31 const response = await fetch(typo3Url.toString(), { headers });
32
33 if (!response.ok) {
34 return NextResponse.json(
35 { error: `TYPO3 API error: ${response.status} ${response.statusText}` },
36 { status: response.status }
37 );
38 }
39
40 const data = await response.json();
41 return NextResponse.json(data);
42 } catch (error) {
43 const message = error instanceof Error ? error.message : 'Unknown error';
44 return NextResponse.json({ error: message }, { status: 500 });
45 }
46}

Pro tip: TYPO3 Headless returns content in a structured 'content' object where each content element has a 'type' field (like 'textmedia', 'textpic', 'bullets', 'table'). You will need to build a content renderer component that maps each TYPO3 content type to the corresponding React component.

Expected result: Calling /api/typo3/page?slug=/ in the Bolt preview returns a JSON object with the TYPO3 page data including page title, meta information, breadcrumbs, and an array of content elements.

3

Build the Content Renderer and Page Components

TYPO3 content is structured differently from a simple blog CMS. Each page contains a 'colPos' system (content columns) and an array of content elements, where each element has a 'type' field (such as textmedia, textpic, bullets, table, shortcut, menu_sitemap, and custom types from installed extensions). Your React frontend needs a content renderer component that maps each TYPO3 content type to a React component. This is the core architectural piece of a TYPO3 headless frontend. For a minimum viable implementation, handle the most common types: text (plain HTML content), textmedia (text with images), bullets (unordered/ordered lists), header (standalone headings), and table. For types your renderer does not recognize, render a fallback that shows the content type name so you can identify gaps during development. TYPO3 Headless returns richtext HTML in a property called bodytext — render it using dangerouslySetInnerHTML, which is safe here because the content comes from your own trusted TYPO3 installation and is sanitized by TYPO3's built-in HTMLparser. Image data in textmedia elements includes publicUrl for the file path, which is relative to your TYPO3 domain — prepend TYPO3_API_URL to construct the full URL. Once the content renderer is working, build a catch-all route at app/[...slug]/page.tsx that fetches from /api/typo3/page with the current URL slug and passes the response to the content renderer.

Bolt.new Prompt

Build a TYPO3 content renderer for this Next.js project. Create a component at components/TYPO3ContentRenderer.tsx that accepts a 'content' array (TYPO3 Headless content elements). Render each element based on its 'type' field: for type 'text' or 'textmedia' render bodytext as HTML using dangerouslySetInnerHTML in a prose Tailwind container; for type 'bullets' render a styled list from a 'bullets' array property; for type 'header' render the 'header' property as an h2; for type 'table' render a styled HTML table from a 'bodytext' property. Add a fallback for unrecognized types showing the type name in gray text. Then create a catch-all page at app/[...slug]/page.tsx that fetches from /api/typo3/page with the joined slug path and renders the result using TYPO3ContentRenderer. Show the page title as h1.

Paste this in Bolt.new chat

components/TYPO3ContentRenderer.tsx
1// components/TYPO3ContentRenderer.tsx
2'use client';
3
4interface TYPO3ContentElement {
5 type: string;
6 uid: number;
7 pid: number;
8 header?: string;
9 bodytext?: string;
10 bullets?: string[];
11 media?: Array<{
12 publicUrl: string;
13 properties: { title: string; alternative: string };
14 }>;
15 [key: string]: unknown;
16}
17
18interface Props {
19 content: TYPO3ContentElement[];
20 baseUrl: string;
21}
22
23export function TYPO3ContentRenderer({ content, baseUrl }: Props) {
24 return (
25 <div className="space-y-8">
26 {content.map((element) => (
27 <div key={element.uid}>
28 {renderElement(element, baseUrl)}
29 </div>
30 ))}
31 </div>
32 );
33}
34
35function renderElement(element: TYPO3ContentElement, baseUrl: string) {
36 switch (element.type) {
37 case 'text':
38 case 'textmedia':
39 case 'textpic':
40 return (
41 <div>
42 {element.header && (
43 <h2 className="text-2xl font-bold text-gray-900 mb-4">{element.header}</h2>
44 )}
45 {element.media && element.media.length > 0 && (
46 <img
47 src={`${baseUrl}${element.media[0].publicUrl}`}
48 alt={element.media[0].properties?.alternative || element.header || ''}
49 className="w-full rounded-lg mb-4 object-cover"
50 />
51 )}
52 {element.bodytext && (
53 <div
54 className="prose prose-lg max-w-none"
55 dangerouslySetInnerHTML={{ __html: element.bodytext }}
56 />
57 )}
58 </div>
59 );
60
61 case 'header':
62 return (
63 <h2 className="text-3xl font-bold text-gray-900">
64 {element.header}
65 </h2>
66 );
67
68 case 'bullets':
69 return (
70 <div>
71 {element.header && (
72 <h2 className="text-2xl font-bold text-gray-900 mb-3">{element.header}</h2>
73 )}
74 <ul className="list-disc list-inside space-y-2 text-gray-700">
75 {(element.bullets || []).map((item, i) => (
76 <li key={i}>{item}</li>
77 ))}
78 </ul>
79 </div>
80 );
81
82 default:
83 return (
84 <div className="p-4 bg-gray-50 rounded border border-gray-200 text-sm text-gray-400">
85 Unsupported content type: {element.type}
86 </div>
87 );
88 }
89}

Pro tip: TYPO3 uses colPos values (0, 1, 2, 3...) to identify content columns. If your page has a sidebar, colPos 0 is usually the main content and colPos 1 the sidebar. The Headless extension groups content elements by colPos in the response — filter the array by colPos before passing it to TYPO3ContentRenderer.

Expected result: Navigating to any page path in the Bolt preview fetches the corresponding TYPO3 page data and renders the content elements using the type-based renderer, with text, images, headers, and bullet lists displaying correctly.

4

Add Multi-Language Support Using TYPO3 Language Configuration

TYPO3's multi-language support is one of its most powerful enterprise features, and the Headless extension passes language configuration through to the JSON response. In a TYPO3 site, each language has a unique languageId (0 for the default language, 1, 2, 3 for additional languages) and a base path (such as /en/, /de/, /fr/). The Headless API exposes the list of configured site languages in a siteLanguages endpoint, which your frontend can use to generate language switcher links. To request content in a specific language, the standard approach is to pass the language's base path as part of the URL — TYPO3 determines the language from the URL prefix based on your site configuration. Alternatively, some setups use an Accept-Language header or a languageId query parameter. Check your specific TYPO3 site configuration to confirm which approach is configured. The React language switcher component should read the available languages from the TYPO3 API and render links to the equivalent page in each language. TYPO3 handles language fallbacks automatically — if a translation does not exist, it falls back to the default language content based on the configured fallback type. One important note: the language-specific page URLs in TYPO3 are managed in the TYPO3 backend and cannot be changed from the Bolt frontend. Content editors add and manage translations entirely within the TYPO3 backend editorial workflow.

Bolt.new Prompt

Add multi-language support to this TYPO3 headless Next.js project. Create an API route at app/api/typo3/languages/route.ts that fetches available languages from process.env.TYPO3_API_URL with query params type=834&tx_headless_page[action]=languages. Return the array of language objects with id, title, twoLetterIsoCode, and base properties. Then create a LanguageSwitcher component that fetches available languages on mount and renders flag or label links. The current language should be detected from the URL path prefix. Place the LanguageSwitcher in the site header.

Paste this in Bolt.new chat

app/api/typo3/languages/route.ts
1// app/api/typo3/languages/route.ts
2import { NextResponse } from 'next/server';
3
4export async function GET() {
5 const apiUrl = process.env.TYPO3_API_URL;
6 if (!apiUrl) {
7 return NextResponse.json({ error: 'TYPO3_API_URL not configured' }, { status: 500 });
8 }
9
10 const url = new URL(apiUrl);
11 url.searchParams.set('type', '834');
12 url.searchParams.set('tx_headless_page[action]', 'languages');
13 url.searchParams.set('tx_headless_page[controller]', 'Page');
14
15 try {
16 const response = await fetch(url.toString(), {
17 headers: { 'Accept': 'application/json' },
18 });
19
20 if (!response.ok) {
21 return NextResponse.json(
22 { error: `TYPO3 languages API error: ${response.status}` },
23 { status: response.status }
24 );
25 }
26
27 const data = await response.json();
28 // TYPO3 Headless returns languages in data.siteLanguages or data.languages
29 const languages = data.siteLanguages || data.languages || [];
30 return NextResponse.json({ languages });
31 } catch (error) {
32 const message = error instanceof Error ? error.message : 'Unknown error';
33 return NextResponse.json({ error: message }, { status: 500 });
34 }
35}

Pro tip: If your TYPO3 site uses language fallbacks (where untranslated content falls back to the default language), the Headless API handles this automatically. You do not need to implement fallback logic in React — TYPO3 always returns the correct content for the requested language based on the site configuration.

Expected result: The /api/typo3/languages endpoint returns an array of configured TYPO3 site languages. The LanguageSwitcher component renders language links in the header, and clicking a language link loads the page content in that language.

5

Deploy to Netlify and Configure Production Environment Variables

Your TYPO3 Headless frontend works in Bolt's WebContainer preview because all TYPO3 API calls are outbound HTTP requests from the server-side API routes — outbound calls to external servers work correctly in the WebContainer development environment. When you are ready to deploy for public access, connect your Bolt project to Netlify through Settings → Applications → Netlify → Connect. Bolt will build the Next.js project and deploy it to a *.netlify.app URL. After the initial deployment, go to your Netlify dashboard → Site Configuration → Environment Variables and add TYPO3_API_URL (your full TYPO3 site URL) and TYPO3_API_TOKEN if you are using authentication. Trigger a redeploy from the Netlify dashboard for the variables to take effect. One critical WebContainer limitation to understand: incoming webhooks from TYPO3 cannot reach the Bolt preview URL. Bolt's WebContainer runs inside a browser tab and does not expose a public-facing HTTP server, so TYPO3 cache invalidation hooks, workflow notifications, and editorial callbacks all require your deployed Netlify URL. After deployment, configure any TYPO3 extension webhooks or cache-invalidation hooks to point at your Netlify URL. If you are using Next.js on-demand revalidation to keep content fresh after TYPO3 publishes, build a revalidation endpoint that accepts a POST request with a secret token, calls revalidatePath for the affected pages, and configure TYPO3 to call this endpoint on page publish using the TYPO3 Headless extension's built-in cache invalidation hooks.

Bolt.new Prompt

Add a cache revalidation endpoint to this Next.js project for TYPO3 Headless. Create an API route at app/api/typo3/revalidate/route.ts that accepts a POST request. Verify a secret token from the Authorization header matches process.env.TYPO3_REVALIDATE_SECRET. Parse the request body for a 'slug' field containing the TYPO3 page slug. Call revalidatePath for the affected slug and for the root path. Return 200 with revalidated: true on success, or 401 if the token is missing or wrong.

Paste this in Bolt.new chat

app/api/typo3/revalidate/route.ts
1// app/api/typo3/revalidate/route.ts
2import { NextResponse } from 'next/server';
3import { revalidatePath } from 'next/cache';
4
5export async function POST(request: Request) {
6 const authHeader = request.headers.get('authorization');
7 const secret = authHeader?.replace('Bearer ', '');
8
9 if (!secret || secret !== process.env.TYPO3_REVALIDATE_SECRET) {
10 return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
11 }
12
13 try {
14 const body = await request.json();
15 const slug = body?.slug as string | undefined;
16
17 // Always revalidate the root page
18 revalidatePath('/');
19
20 // Revalidate the specific slug if provided
21 if (slug) {
22 const cleanSlug = slug.startsWith('/') ? slug : `/${slug}`;
23 revalidatePath(cleanSlug);
24 }
25
26 return NextResponse.json({ revalidated: true, slug: slug || '/' });
27 } catch {
28 return NextResponse.json({ error: 'Revalidation failed' }, { status: 500 });
29 }
30}

Pro tip: Set TYPO3_REVALIDATE_SECRET in Netlify's environment variables, then configure the TYPO3 Headless extension's cache invalidation settings in the TYPO3 backend to call your deployed /api/typo3/revalidate endpoint whenever a page is published or updated.

Expected result: Your TYPO3 headless frontend is deployed on Netlify. TYPO3 content appears on the deployed site, and the revalidation endpoint refreshes cached pages when editors publish updates in the TYPO3 backend.

Common use cases

Enterprise Website with Existing TYPO3 Backend

Replace an outdated TYPO3 frontend theme with a modern React application while keeping all content, editorial workflows, and access control in TYPO3. Content editors continue using the familiar TYPO3 backend, while the React frontend delivers improved performance, design flexibility, and the ability to integrate modern JavaScript tools.

Bolt.new Prompt

Build a headless TYPO3 CMS integration in this Next.js project. Create an API route at app/api/typo3/page/route.ts that fetches a page from TYPO3 Headless API using process.env.TYPO3_API_URL. Accept a 'slug' query parameter and call TYPO3_API_URL + '?type=834&tx_headless_page[action]=page&tx_headless_page[slug]=' + slug. Return the page title, content elements array, and metadata. Display the page content in a React component at app/[...slug]/page.tsx.

Copy this prompt to try it in Bolt.new

Multi-Language Corporate Portal

Fetch TYPO3's structured multi-language content through the Headless API and render language-specific pages in React. TYPO3 manages translations and language overlays natively, and the Headless extension passes the language configuration through to the JSON response, allowing the React frontend to implement language switching without duplicating content.

Bolt.new Prompt

Create a multi-language page in Next.js using TYPO3 Headless API. Build an API route at app/api/typo3/languages/route.ts that fetches available languages from process.env.TYPO3_API_URL with the siteLanguages request type. Then modify the main page fetch API route to accept a 'language' query parameter and pass it as the Accept-Language header to the TYPO3 API. Add a language switcher component that reads available languages and links to the correct locale URL.

Copy this prompt to try it in Bolt.new

TYPO3 Navigation and Menu Tree

Fetch TYPO3's page tree as a structured menu using the Headless API's navigation endpoint and render it as a dynamic sidebar or top navigation in React. TYPO3's menu generation respects page access permissions and doktype settings, so hidden pages and access-restricted sections are automatically excluded from the JSON response.

Bolt.new Prompt

Build a navigation component for this Next.js project that fetches the site menu from TYPO3 Headless API. Create an API route at app/api/typo3/navigation/route.ts that calls process.env.TYPO3_API_URL with type=834 and tx_headless_page[action]=menu. Parse the returned navigation tree and render a responsive header nav component with support for nested dropdown menus up to two levels deep. Use Tailwind CSS for styling.

Copy this prompt to try it in Bolt.new

Troubleshooting

TYPO3 Headless API returns HTML instead of JSON when calling ?type=834

Cause: The headless: true setting is missing from the TYPO3 site configuration, the EXT:headless extension is not activated, or the type parameter is being ignored by a routing configuration.

Solution: Open Admin Tools → Extensions in the TYPO3 backend and verify EXT:headless appears in the active extensions list. Then open your site configuration file at config/sites/your-site/config.yaml and confirm headless: true is present at the root level. Clear TYPO3's caches (Maintenance → Flush Cache) after making configuration changes. Test by visiting yoursite.com/?type=834 directly in a browser.

CORS error when calling the TYPO3 Headless API from a React component

Cause: TYPO3 does not include CORS headers for cross-origin browser requests by default, so direct client-side fetch calls from the Bolt preview to the TYPO3 domain fail.

Solution: Route all TYPO3 API calls through the Next.js API routes at /api/typo3/* rather than calling the TYPO3 URL directly from client components. The API routes execute server-side and are not subject to browser CORS restrictions.

typescript
1// Wrong — direct call from client component
2const res = await fetch('https://your-typo3.com/?type=834');
3
4// Correct — call through your API route
5const res = await fetch('/api/typo3/page?slug=/');

TYPO3 content images show broken image errors in the Bolt preview

Cause: TYPO3 Headless returns image paths as relative URLs (e.g., /fileadmin/images/photo.jpg) that are relative to the TYPO3 domain, not the Bolt preview URL.

Solution: Prepend the TYPO3_API_URL base domain to all image publicUrl values returned by the TYPO3 Headless API before rendering them in img tags. Pass the base URL as a prop to the TYPO3ContentRenderer component or use a utility function to normalize image URLs.

typescript
1// Normalize image URL in TYPO3ContentRenderer
2function getAbsoluteImageUrl(relativeUrl: string, baseUrl: string): string {
3 if (relativeUrl.startsWith('http')) return relativeUrl;
4 const base = new URL(baseUrl);
5 return `${base.protocol}//${base.host}${relativeUrl}`;
6}
7
8// Usage
9<img src={getAbsoluteImageUrl(element.media[0].publicUrl, process.env.NEXT_PUBLIC_TYPO3_BASE_URL!)} />

TYPO3 cache invalidation webhooks do not reach the Bolt preview URL

Cause: Bolt's WebContainer runs inside a browser tab and cannot accept incoming HTTP connections from external services — there is no public-facing HTTP server in the development environment.

Solution: Deploy to Netlify or Vercel first to get a stable public URL. Configure the TYPO3 Headless cache invalidation settings in the TYPO3 backend to point at your deployed URL's /api/typo3/revalidate endpoint. The Bolt preview is suitable for building and testing outbound API calls only — incoming webhooks from TYPO3 require a deployed environment.

Best practices

  • Never expose TYPO3_API_TOKEN as a NEXT_PUBLIC_ variable — keep all TYPO3 credentials in server-side environment variables accessed only from API routes
  • Build a comprehensive TYPO3ContentRenderer that handles all content element types used on your site — log unknown types during development so you can identify gaps before launch
  • Use Next.js fetch caching with revalidate intervals for TYPO3 content that changes infrequently, and on-demand revalidation for content that editors publish frequently
  • Prepend the TYPO3 base URL to all relative image publicUrl paths returned by the Headless API before rendering img elements
  • Test TYPO3 API calls in the Bolt WebContainer preview before deploying — outbound calls to your TYPO3 server work correctly in the development environment
  • For multi-site TYPO3 setups, use separate environment variables per site (TYPO3_SITE1_API_URL, TYPO3_SITE2_API_URL) and route API requests based on the current hostname
  • Configure TYPO3's cache invalidation hooks to call your Netlify revalidation endpoint after every page publish so the React frontend always reflects the latest content
  • For new projects without an existing TYPO3 installation, consider WordPress or Ghost as simpler headless CMS alternatives — TYPO3 requires a PHP server and more configuration overhead

Alternatives

Frequently asked questions

Does Bolt.new work with TYPO3?

Yes. Bolt.new connects to TYPO3 through the TYPO3 Headless extension (EXT:headless), which exposes a JSON API for pages and content elements. You build Next.js API routes in Bolt that proxy requests to your TYPO3 instance, and React components consume the JSON data to render the frontend. Outbound API calls to TYPO3 work correctly in Bolt's WebContainer development preview.

Do I need to install any TYPO3 extensions to use it with Bolt.new?

Yes. TYPO3 does not include a headless JSON API out of the box. You need to install the EXT:headless extension via Composer (composer require friendsoftypo3/headless) and enable headless: true in your site configuration. If your site uses EXT:news or EXT:blog, install the companion headless_news or headless_blog extensions to get JSON support for those content types as well.

Can I use Bolt.new with TYPO3 if I do not have server access?

Not directly. The TYPO3 Headless extension requires Composer installation and access to TYPO3's site configuration files, which means you need server-level access to your TYPO3 installation. If you are using a managed TYPO3 hosting provider, check whether they support Composer-based extension installation. For users without server access, WordPress with its built-in REST API is a simpler alternative.

How do I handle TYPO3 multi-language content in Bolt.new?

TYPO3 Headless passes language configuration through to the JSON API. Fetch available languages from the languages endpoint and render language switcher links in your React header component. Language-specific content is served automatically by TYPO3 based on the URL prefix path — no additional language mapping is needed in the React code. TYPO3 manages translation fallbacks automatically based on your site configuration.

Can TYPO3 webhooks reach the Bolt.new development preview?

No. Bolt's WebContainer runs inside a browser tab and cannot accept incoming HTTP connections — there is no public server in the development environment. TYPO3 cache invalidation hooks, editorial workflow notifications, and any other incoming webhooks require a deployed environment. Deploy to Netlify first, then configure TYPO3 to call your deployed URL's revalidation endpoint.

Is TYPO3 a good choice for new projects using Bolt.new?

TYPO3 is an excellent choice if you are connecting to an existing TYPO3 installation, particularly in German-speaking markets where TYPO3 is widely used. For new projects starting from scratch, the setup overhead (PHP server, Composer, extension installation) makes WordPress or Ghost simpler alternatives. TYPO3 shines for large-scale multi-site and multi-language requirements that outgrow simpler CMSs.

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.