Movable Type to Next.js Migration Guide for Japanese Companies
If you've worked with Japanese enterprise websites for any length of time, you've almost certainly encountered Movable Type. Six Apart's CMS has had a remarkably strong grip on the Japanese market since the mid-2000s, powering everything from corporate sites at major manufacturers to government portals and university websites. But here's the thing -- it's 2026, and the web has moved on. Your Movable Type installation probably hasn't.
I've helped migrate several Japanese enterprise sites off Movable Type over the past two years, and I'll be honest: it's not a trivial project. There are quirks around character encoding, content structures unique to Japanese corporate sites, and organizational concerns that make these migrations different from your typical WordPress-to-Next.js move. This guide covers everything I've learned the hard way.

Table of Contents
- Why Japanese Companies Are Leaving Movable Type
- Understanding Movable Type's Architecture
- Choosing Your Headless CMS Backend
- Content Audit and Data Extraction
- Handling Japanese Content Specifics
- Building the Next.js Frontend
- SEO Migration Strategy for Japanese Search
- Deployment and Infrastructure
- Timeline and Budget Planning
- FAQ
Why Japanese Companies Are Leaving Movable Type
Let's get the obvious out of the way: Movable Type isn't dead. Six Apart Japan still maintains it, and Movable Type 8 (released in late 2024) added some modern features. But the writing is on the wall for several reasons.
Performance Concerns
Movable Type uses a static publishing model -- it rebuilds HTML files when content changes. This sounds great until you have a site with 15,000 pages and a content editor waiting 20 minutes for a rebuild to finish. I've seen Japanese corporate sites where editors would schedule rebuilds overnight because the process was so slow.
Next.js with ISR (Incremental Static Regeneration) or on-demand revalidation solves this completely. Pages regenerate individually in milliseconds.
Cost of Ownership
Movable Type licensing in Japan runs roughly ¥600,000-¥1,200,000 per year for enterprise licenses as of 2026. That's $4,000-$8,000 USD annually just for the CMS license, before hosting, plugins, or custom development. Compare that to a headless CMS like microCMS (popular in Japan, starting at ¥4,900/month for business plans) paired with Next.js on Vercel, and the math starts looking very different.
Developer Shortage
This is the big one nobody talks about publicly. Finding developers who know Perl (Movable Type's language) and are willing to work on MT templates is getting genuinely difficult in Japan. The median age of MT-experienced developers I've encountered is north of 45. Meanwhile, Next.js developers are everywhere -- it's the framework Japanese tech companies are hiring for in 2026.
Security and Compliance
Movable Type has had several serious CVEs over the years, including the infamous XMLRPC vulnerability (CVE-2021-20837) that was actively exploited against Japanese sites. With Japan's amended APPI (Act on the Protection of Personal Information) requirements tightening in 2025-2026, companies are re-evaluating their security posture.
Understanding Movable Type's Architecture
Before you can migrate, you need to understand what you're migrating from. Movable Type's data model is different from WordPress or most modern CMSes.
Core Data Structures
| MT Concept | Description | Next.js/Headless Equivalent |
|---|---|---|
| Blog | Top-level content container | Site or workspace |
| Entry | Blog post or article | Content item (blog type) |
| Page | Static page | Content item (page type) |
| Category | Hierarchical taxonomy | Category/tag system |
| Template | HTML templates with MT tags | React components + layouts |
| Custom Field | Extended entry fields | Content model fields |
| Asset | Uploaded media files | Media/asset library |
| Website | Parent container for blogs | Multi-site configuration |
Movable Type's template language uses tags like <mt:EntryTitle> and <mt:Entries>. These don't map 1:1 to anything in the modern stack -- you'll be rebuilding the presentation layer from scratch.
The Database Layer
MT supports MySQL, PostgreSQL, and SQLite. Most Japanese enterprise installations use MySQL. The database schema is well-documented but... eccentric. Custom fields are stored in a separate mt_entry_meta table using a key-value pattern, which makes extraction non-trivial.
Here's what the entry table looks like:
SELECT
entry_id,
entry_title,
entry_text,
entry_text_more,
entry_excerpt,
entry_created_on,
entry_modified_on,
entry_basename,
entry_status
FROM mt_entry
WHERE entry_blog_id = 1
AND entry_status = 2 -- 2 = published
ORDER BY entry_created_on DESC;
Note the entry_text and entry_text_more split. MT splits body content into two fields -- a pattern from the early blogging era that you'll need to concatenate during migration.

Choosing Your Headless CMS Backend
Next.js is your frontend framework. But you need somewhere to manage content. For Japanese companies, I've narrowed it down to four realistic options.
microCMS
This is the default choice for Japanese companies, and for good reason. It's built by a Japanese company, has native Japanese UI, Japanese customer support, and data residency in Japan. Pricing starts at ¥4,900/month (Hobby is free for small projects). The API is clean, the webhook support works well with Next.js ISR, and your content editors won't need English skills.
Newt
Another Japanese-made headless CMS that's been gaining traction. It's slightly more developer-friendly than microCMS and has better content modeling flexibility. Good option if your site has complex content structures.
Contentful
The global enterprise choice. Strong localization support, excellent API, and a mature ecosystem. The downside for Japanese companies: support is in English, the UI is in English, and pricing is in USD. At $300/month for the Team plan (2026 pricing), it's significantly more expensive than Japanese alternatives.
Sanity
I mention Sanity because it's technically excellent, and its customizable Studio can be configured with Japanese labels. But the learning curve is steeper, and you won't find as many Japanese developers with Sanity experience.
| CMS | Japanese UI | Japan Data Residency | Starting Price | Best For |
|---|---|---|---|---|
| microCMS | ✅ | ✅ | ¥4,900/mo | Most Japanese corporate sites |
| Newt | ✅ | ✅ | ¥3,300/mo | Complex content models |
| Contentful | ❌ | ❌ (EU/US) | ~$300/mo | Global enterprises |
| Sanity | Partial | ❌ | $99/mo (Team) | Developer-heavy teams |
For most Japanese companies migrating from Movable Type, I recommend microCMS or Newt. The friction reduction of having everything in Japanese is worth more than you'd think. We've worked extensively with all of these through our headless CMS development practice.
Content Audit and Data Extraction
This is where the real work begins. Don't skip the audit phase -- I've seen migrations fail because teams jumped straight to extraction without understanding what they actually had.
Step 1: Inventory Everything
Connect to your MT database and run counts:
-- Count entries by blog
SELECT
b.blog_name,
COUNT(e.entry_id) as entry_count
FROM mt_entry e
JOIN mt_blog b ON e.entry_blog_id = b.blog_id
WHERE e.entry_status = 2
GROUP BY b.blog_name;
-- Count custom fields per blog
SELECT
b.blog_name,
em.entry_meta_type,
COUNT(*) as field_count
FROM mt_entry_meta em
JOIN mt_entry e ON em.entry_meta_entry_id = e.entry_id
JOIN mt_blog b ON e.entry_blog_id = b.blog_id
GROUP BY b.blog_name, em.entry_meta_type;
Step 2: Export Content
MT has a built-in export format, but it's limited. I prefer direct database extraction with a Python script:
import mysql.connector
import json
import html
def extract_mt_entries(config):
conn = mysql.connector.connect(**config)
cursor = conn.cursor(dictionary=True)
cursor.execute("""
SELECT
e.entry_id,
e.entry_title,
e.entry_text,
e.entry_text_more,
e.entry_excerpt,
e.entry_basename,
e.entry_created_on,
e.entry_modified_on,
GROUP_CONCAT(c.category_label) as categories
FROM mt_entry e
LEFT JOIN mt_placement p ON e.entry_id = p.placement_entry_id
LEFT JOIN mt_category c ON p.placement_category_id = c.category_id
WHERE e.entry_status = 2
GROUP BY e.entry_id
""")
entries = cursor.fetchall()
for entry in entries:
# Combine text and text_more
body = (entry['entry_text'] or '') + (entry['entry_text_more'] or '')
entry['full_body'] = body
# Handle encoding
entry['entry_title'] = entry['entry_title']
with open('mt_export.json', 'w', encoding='utf-8') as f:
json.dump(entries, f, ensure_ascii=False, default=str, indent=2)
return entries
Step 3: Media Asset Migration
MT stores assets on the filesystem, usually under /path/to/mt/support/uploads/. You'll need to:
- Inventory all files and match them to database records in
mt_asset - Re-upload to your new CMS or a CDN (Cloudinary, imgix, or your CMS's built-in storage)
- Update all references in your content body HTML
This is tedious. Budget time for it.
Handling Japanese Content Specifics
This section is why I wrote this article. Generic migration guides don't cover these issues.
Character Encoding
Older Movable Type installations (pre-MT5) sometimes stored content in EUC-JP or Shift_JIS encoding, even if the database was nominally UTF-8. Check your actual data:
# Detect encoding issues
import chardet
def check_encoding(text_bytes):
result = chardet.detect(text_bytes)
if result['encoding'] != 'utf-8':
print(f"Warning: detected {result['encoding']} "
f"with {result['confidence']:.0%} confidence")
return result
If you find encoding mismatches, convert everything to UTF-8 before importing into your new CMS. Broken mojibake (文字化け) on a corporate site is a career-limiting event.
Ruby Text (Furigana)
Japanese corporate sites frequently use ruby annotations -- small reading aids above kanji characters. MT templates often handle these with custom tags. In Next.js, you'll use standard HTML <ruby> elements:
// components/RubyText.tsx
export function RubyText({ base, reading }: { base: string; reading: string }) {
return (
<ruby>
{base}
<rp>(</rp>
<rt>{reading}</rt>
<rp>)</rp>
</ruby>
);
}
Make sure your content migration script preserves any existing ruby markup.
Japanese Date Formatting
Japanese corporate sites often display dates in 和暦 (Japanese era format): 令和8年1月15日 instead of 2026-01-15. Handle this in your Next.js components:
function formatJapaneseDate(dateString: string): string {
const date = new Date(dateString);
return date.toLocaleDateString('ja-JP-u-ca-japanese', {
era: 'long',
year: 'numeric',
month: 'long',
day: 'numeric',
});
}
Vertical Text Layouts
Some Japanese sites, particularly in publishing or traditional industries, use vertical text (縦書き). CSS handles this:
.vertical-text {
writing-mode: vertical-rl;
text-orientation: mixed;
}
Next.js handles this fine, but test thoroughly across browsers.
Building the Next.js Frontend
With your content extracted and your CMS chosen, it's time to build. Here's the architecture I recommend for Japanese corporate sites.
App Router with Static Generation
Use Next.js 15's App Router with static generation for most pages. Japanese corporate sites are typically content-heavy with infrequent updates -- perfect for static generation with on-demand revalidation.
// app/news/[slug]/page.tsx
import { getArticle, getAllArticleSlugs } from '@/lib/cms';
export async function generateStaticParams() {
const slugs = await getAllArticleSlugs();
return slugs.map((slug) => ({ slug }));
}
export default async function NewsArticle({
params
}: {
params: Promise<{ slug: string }>
}) {
const { slug } = await params;
const article = await getArticle(slug);
return (
<article>
<h1>{article.title}</h1>
<time dateTime={article.publishedAt}>
{formatJapaneseDate(article.publishedAt)}
</time>
<div dangerouslySetInnerHTML={{ __html: article.body }} />
</article>
);
}
i18n Configuration
Many Japanese corporate sites need both Japanese and English versions. Next.js App Router handles this with route groups or middleware-based locale detection:
// middleware.ts
import { NextRequest, NextResponse } from 'next/server';
export function middleware(request: NextRequest) {
const pathname = request.nextUrl.pathname;
const locale = pathname.startsWith('/en') ? 'en' : 'ja';
request.headers.set('x-locale', locale);
return NextResponse.next();
}
We've built dozens of bilingual Japanese corporate sites using Next.js -- our Next.js development team can walk you through the nuances.
SEO Migration Strategy for Japanese Search
This is non-negotiable. Japanese companies live and die by their Google search rankings (Yahoo! Japan uses Google's engine, so it's really just Google). A botched migration can tank organic traffic for months.
URL Mapping
Movable Type generates URLs with configurable patterns. Common ones I see on Japanese sites:
/blog/2024/01/entry-basename.html/news/category/entry_basename.html/archives/000123.html(the oldest pattern)
Create a complete URL mapping before you build anything:
// scripts/generate-redirects.ts
interface RedirectMap {
source: string;
destination: string;
permanent: boolean;
}
function generateRedirects(mtEntries: MTEntry[]): RedirectMap[] {
return mtEntries.map(entry => ({
source: buildMTUrl(entry), // Old MT URL pattern
destination: `/news/${entry.entry_basename}`, // New Next.js URL
permanent: true, // 301 redirect
}));
}
Put these in your next.config.ts:
const nextConfig = {
async redirects() {
const redirects = await import('./redirects.json');
return redirects.default;
},
};
For sites with thousands of redirects, use middleware instead -- next.config.ts redirects have a practical limit.
Structured Data
Japanese Google results heavily feature rich snippets. Add JSON-LD for articles, FAQs, and organization info:
function ArticleJsonLd({ article }: { article: Article }) {
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'Article',
headline: article.title,
datePublished: article.publishedAt,
dateModified: article.updatedAt,
author: {
'@type': 'Organization',
name: article.companyName,
},
inLanguage: 'ja',
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
);
}
Deployment and Infrastructure
For Japanese audiences, latency matters. Here's what works:
| Platform | Japan Edge Nodes | Best For | Monthly Cost (typical) |
|---|---|---|---|
| Vercel | Tokyo | Most Next.js sites | $20-150/mo |
| AWS (CloudFront + Lambda@Edge) | Tokyo, Osaka | Enterprise compliance | $100-500/mo |
| Google Cloud Run + Cloud CDN | Tokyo | GCP-native teams | $50-200/mo |
| Cloudflare Pages | Tokyo + many | Simple static sites | Free-$25/mo |
Vercel is my default recommendation. It's purpose-built for Next.js, has a Tokyo edge node, and the DX is unmatched. For companies with strict data residency requirements (government, financial), AWS in ap-northeast-1 (Tokyo) is the safe choice.
If you're considering Astro instead of Next.js for a content-heavy site with minimal interactivity, that's a valid choice too -- check our Astro development capabilities.
Timeline and Budget Planning
Based on actual migrations I've completed, here's what to expect:
| Phase | Duration | Key Activities |
|---|---|---|
| Discovery & Audit | 2-3 weeks | Content inventory, stakeholder interviews, URL mapping |
| CMS Setup & Content Modeling | 2-4 weeks | Schema design, content migration scripts |
| Content Migration | 3-6 weeks | Data transfer, media migration, QA |
| Frontend Development | 6-10 weeks | Next.js build, component library, i18n |
| SEO & QA | 2-3 weeks | Redirect testing, performance tuning, cross-browser QA |
| Staged Rollout | 1-2 weeks | DNS cutover, monitoring, hotfixes |
Total: 16-28 weeks for a typical Japanese corporate site with 1,000-10,000 pages.
Budget-wise, you're looking at ¥5,000,000-¥15,000,000 ($33,000-$100,000 USD) depending on complexity. That might seem like a lot, but consider: you're likely paying ¥1,000,000+ annually for MT licensing and specialized development already. The migration pays for itself within 2-3 years through reduced operational costs and improved developer velocity.
Need a detailed estimate for your specific situation? Reach out to us or check our pricing page for engagement models.
FAQ
Can we keep using Movable Type as a headless CMS with Next.js?
Technically yes -- Movable Type 7+ has a Data API that can serve content to a frontend. But it's slow, poorly documented, and lacks webhooks for revalidation. I've tried this approach on one project and wouldn't recommend it. You'll spend more time working around MT's API limitations than you would migrating to a proper headless CMS.
How do we handle the MT rebuild model vs. Next.js ISR?
They're fundamentally different. MT rebuilds entire site sections at once (batch static generation). Next.js ISR regenerates individual pages on demand. This means your editors get instant publish times instead of waiting for rebuilds. The mental model shift is actually easier for editors -- they just hit publish and the page is live within seconds.
What happens to our MT plugins during migration?
Every MT plugin needs a replacement or re-implementation. Common ones like contact forms (MT-based form plugins) get replaced with Next.js form handling or services like Formspree. Search plugins get replaced with Algolia or the CMS's built-in search. Make a complete plugin inventory during the audit phase.
Will our Google rankings drop during migration?
They can, but they don't have to. The critical factors are: 301 redirects for every URL, maintaining identical or improved page titles and meta descriptions, preserving internal link structure, and submitting an updated sitemap. I've seen migrations where rankings actually improved because the new site was faster and had better Core Web Vitals scores.
How do we handle Japanese-specific SEO elements like Yahoo! Japan?
Yahoo! Japan has used Google's search engine since 2010, so your Google SEO strategy covers Yahoo! too. The one exception is Yahoo! Japan's own properties (Yahoo! News, etc.) which have separate submission processes. For general organic search, focus on Google and you're covered.
Should we migrate all content or use this as an opportunity to clean up?
Always clean up. In every Japanese corporate site migration I've done, 30-50% of content was outdated, redundant, or had zero traffic. Migrating dead content wastes time and dilutes your site's topical authority. Use analytics data to identify pages worth migrating and let the rest go (with proper 410 Gone responses, not 404s).
Can we run Movable Type and Next.js in parallel during migration?
Yes, and I recommend it. Use a subdomain or path-based routing to serve the new Next.js site for migrated sections while MT handles the rest. This lets you migrate in phases rather than doing a risky big-bang cutover. Reverse proxy configurations with nginx or Cloudflare Workers make this straightforward.
What about Movable Type's built-in access control and member features?
If your MT site uses member login, gated content, or role-based access, you'll need to implement authentication in Next.js. NextAuth.js (now Auth.js) works well for this, or you can use a service like Clerk or Auth0. This adds complexity and cost -- factor it into your planning from day one.