In this article
JobKorea (잡코리아) and its sister platform Albamon are Korea's dominant recruiting platforms. Together, they serve millions of job seekers and employers — from fresh graduates hunting their first gig to senior professionals navigating career transitions.
In February 2026, their engineering team published a detailed breakdown of how they adopted server-driven UI to solve a problem that will sound painfully familiar to any mobile team: the product team wants a change tomorrow, but the app store says "minimum 3 days."
What they built is one of the cleanest SDUI architectures we've seen in production — and it didn't require a thousand-person platform team to pull off.
The 3-Day Problem
"기획팀에서 '내일까지 홈 화면에 추천 공고 섹션을 추가해주세요'라는 요청이 올 때마다 돌아오는 대답은 항상 같았습니다. '앱은 스토어 심사가 있어서 최소 3일은 걸립니다.'"
"Every time the planning team asked us to add a recommendation section to the home screen by tomorrow, the answer was always the same: 'App store review takes at least 3 days.'"
— JobKorea Engineering Blog, February 2026
Here's what adding a single recommendation section to the home screen actually required:
- iOS team writes the new section in Swift, submits a PR, gets it reviewed, merged
- Android team does the same in Kotlin — independently, with potential design drift
- Web team builds it a third time
- App store review adds 1-3 days on top of development
- User adoption — even after approval, users need to actually update the app
In the recruiting industry, timing matters. Job postings are seasonal. Hiring surges happen fast. By the time a UI change went through the full release cycle, the moment had often passed.
Why They Chose SDUI Over Alternatives
JobKorea considered the usual options before landing on server-driven UI:
WebViews? They'd lose the native feel. In a market where competing job apps feel snappy and native, embedding web content for core screens would be a noticeable UX downgrade. Users in Korea have particularly high expectations for app quality.
Feature flags? Great for toggling features on and off, but they can't rearrange the home screen, add new section types, or change the layout itself. The "what" of the UI is still hardcoded.
More frequent releases? Even daily releases wouldn't solve the app store review bottleneck. And coordinating iOS + Android + Web for every change is expensive regardless of cadence.
Server-driven UI was the only approach that addressed all three constraints at once: instant updates, native rendering, and a single source of truth for the UI across platforms. This is the same conclusion companies like Nubank, Airbnb, and Netflix have reached — though each at different scales and with different architectures.
The Screen/Section Architecture
JobKorea's SDUI system is built on an elegantly simple two-tier model: Screens and Sections.
Screens: The Page Container
A Screen is the top-level definition of a full page in the app. But it's not just "the home page" — it's parameterized across five dimensions:
Screen Targeting Dimensions
- siteType — Which platform:
JOBKOREAorALBAMON - deviceType — What device:
MOBILE_APP,PC, orMOBILE_WEB - screenType — Which page:
HOME,SEARCH_JOB, etc. - segmentType — User segment:
GENERAL,NEWBIE,JUNIOR,SENIOR - testType — A/B test group assignment
This means the same "home screen" can have completely different layouts for a new graduate on the JobKorea mobile app versus a senior professional on Albamon's desktop site — all without any client-side branching logic.
Screen Configuration (JSON){
"screen": {
"siteType": "JOBKOREA",
"deviceType": "MOBILE_APP",
"screenType": "HOME",
"segmentType": "NEWBIE",
"testType": "GROUP_A",
"version": "20260219123045",
"sections": [
{ "sectionId": "HERO_BANNER", "order": 1 },
{ "sectionId": "JOB_RECOMMENDATION", "order": 2 },
{ "sectionId": "TRENDING_KEYWORDS", "order": 3 },
{ "sectionId": "RECENT_VIEWED", "order": 4 },
{ "sectionId": "SALARY_INSIGHTS", "order": 5 }
]
}
}
Sections: Reusable UI Blocks
Sections are where the actual UI lives. Each section is a self-contained block with three key properties:
- A renderType that tells the client how to display it (
CAROUSEL_CARD_SALARY,LIST_CARD_DEFAULT,GRID_CARD_THUMBNAIL, etc.) - Its own apiUrl for loading data independently
- Complete isolation from other sections — one failure doesn't cascade
{
"section": {
"sectionId": "JOB_RECOMMENDATION",
"renderType": "CAROUSEL_CARD_SALARY",
"title": "추천 공고",
"apiUrl": "/api/v1/recommendations?segment=NEWBIE",
"refreshInterval": 300,
"fallback": {
"renderType": "LIST_CARD_DEFAULT",
"apiUrl": "/api/v1/popular-jobs"
}
}
}
The critical insight here: sections are reusable across screens. The same JOB_RECOMMENDATION section can appear on both the HOME screen and the SEARCH_JOB screen. Define it once, use it everywhere.
★ Same section reused across different screens — defined once, rendered everywhere
This is a textbook application of the component-based SDUI pattern, but with an unusually clean separation between page structure (Screen) and reusable content blocks (Section).
How the Data Flows
JobKorea's data pipeline from admin configuration to user screen follows four steps:
Configure screens & sections
Versioned JSON
Cached config store
~100 bytes
Sections load independently
Step 1: Admin configures. A product manager uses the internal management tool to define screens, assign sections, set targeting parameters, and arrange the layout. No engineering required.
Step 2: Publish. When ready, the admin publishes the configuration. A versioned JSON snapshot is created with a timestamp-based version string (e.g., "20260219123045").
Step 3: Redis cache. The published configuration is stored in Redis for fast retrieval. The version string acts as an ETag — clients can check if they need to download a new config without pulling the full payload.
Step 4: Client rendering. The mobile app checks the screen version on each load. If the version hasn't changed, it uses its cached configuration. If it has, it downloads the new config and renders each section independently, with each section fetching its own data from its apiUrl.
// Client-side pseudocode
const localVersion = cache.getVersion("HOME_SCREEN");
const remoteVersion = await api.getScreenVersion({
siteType: "JOBKOREA",
deviceType: "MOBILE_APP",
screenType: "HOME",
segmentType: user.segment,
testType: user.testGroup
});
if (localVersion !== remoteVersion) {
// Download new configuration (~2-5KB)
const screenConfig = await api.getScreenConfig(remoteVersion);
cache.save("HOME_SCREEN", screenConfig);
}
// Render each section independently
for (const section of screenConfig.sections) {
renderSection(section); // Each section loads its own data
}
The elegance here is in the economics: the version check is roughly 100 bytes. For the vast majority of screen loads, the UI configuration hasn't changed, so the app pays almost nothing in network cost.
Built-in A/B Testing
Most teams bolt A/B testing on after the fact — feature flags that toggle between code paths, third-party tools that add latency, or configuration systems that were never designed for experimentation.
JobKorea built it directly into the Screen model via the testType dimension:
// Same page, different experiences — zero code changes
{
"screen": {
"siteType": "JOBKOREA",
"deviceType": "MOBILE_APP",
"screenType": "HOME",
"segmentType": "NEWBIE",
"testType": "GROUP_A", // ← Variant A
"sections": [
{ "sectionId": "JOB_RECOMMENDATION", "order": 1 },
{ "sectionId": "COMPANY_SPOTLIGHT", "order": 2 }
]
}
}
// vs.
{
"screen": {
"siteType": "JOBKOREA",
"deviceType": "MOBILE_APP",
"screenType": "HOME",
"segmentType": "NEWBIE",
"testType": "GROUP_B", // ← Variant B
"sections": [
{ "sectionId": "COMPANY_SPOTLIGHT", "order": 1 },
{ "sectionId": "JOB_RECOMMENDATION", "order": 2 },
{ "sectionId": "TRENDING_SEARCHES", "order": 3 }
]
}
}
Group A sees recommendations first, then company spotlights. Group B gets the reverse order plus a trending searches section. Testing completely different page layouts — not just button colors — without touching a line of client code.
This is exactly the kind of deep experimentation capability that makes the business case for SDUI so compelling. When your product team can test structural changes to the home screen in minutes instead of release cycles, the pace of learning accelerates dramatically.
Resilience: Independent Section Loading
Here's where JobKorea's architecture really shines from a reliability perspective.
Because each section has its own apiUrl and loads data independently, a failure in one section is completely isolated from the rest of the screen:
What Happens When a Section Fails?
- The recommendation API goes down → the recommendation section shows an error state or falls back to a simpler renderType
- The rest of the home screen loads normally — hero banner, trending keywords, salary insights all render independently
- Users might not even notice the degradation unless they're specifically looking for recommendations
This is a massive improvement over monolithic API designs where the home screen makes one big request and a failure anywhere returns nothing. With section-level isolation, your blast radius for any single backend issue is limited to one rectangular block on the page.
The section definition even supports explicit fallbacks:
{
"section": {
"sectionId": "JOB_RECOMMENDATION",
"renderType": "CAROUSEL_CARD_SALARY",
"apiUrl": "/api/v1/recommendations",
"fallback": {
"renderType": "LIST_CARD_DEFAULT",
"apiUrl": "/api/v1/popular-jobs"
}
}
}
If the personalized recommendation API fails, the section automatically falls back to showing popular jobs in a simpler layout. The user still sees content — just a less personalized version of it.
Caching Strategy
JobKorea's caching is version-based and impressively lightweight:
- Version string: Each published screen configuration gets a timestamp-based version like
"20260219123045" - Lightweight check: On each screen load, the client sends the current version to the server (~100 bytes round trip)
- Download only if changed: If the version matches, no further data is transferred. If it's different, the client downloads the new screen config
- Local cache: The downloaded configuration is cached on-device until the next version change
In practice, screen configurations don't change that often — maybe a few times per week for the home screen, less for others. That means 99%+ of screen loads cost only ~100 bytes for the version check. No polling, no WebSocket connections, no background sync.
💡 Why this matters for performance: Many SDUI implementations download the full UI configuration on every screen load, adding latency. JobKorea's version-based approach means the SDUI layer adds virtually zero overhead to the normal app experience — you're paying 100 bytes to check if anything changed. That's smaller than a single tracking pixel. For more on SDUI performance patterns, see our guide on SDUI performance optimization.
What We Can Learn from JobKorea
JobKorea's implementation validates several key principles for any team considering SDUI:
1. You Don't Need a Massive Team
Unlike Nubank's 3,000-engineer operation, JobKorea built a production SDUI system with a much smaller team. Their architecture is simpler — no custom interpreter, no scripting engine — and that's a feature, not a limitation. Simpler systems are easier to build, maintain, debug, and extend.
2. Two Tiers Is Enough
The Screen/Section model is powerful in its simplicity. Screens define what sections appear and in what order. Sections define how data is rendered. That's it. No deeply nested component trees, no recursive layouts, no Turing-complete server expressions. For the vast majority of SDUI use cases — content-heavy screens with mix-and-match blocks — this is all you need.
3. Build Targeting Into the Architecture
Rather than bolting on personalization and A/B testing as afterthoughts, JobKorea made them first-class dimensions of the Screen model. The segmentType and testType fields are right there in the primary key. This is a crucial design decision that pays dividends as the product team's experimentation needs grow.
4. Independent Data Loading Is Non-Negotiable
Each section owning its own API endpoint is what makes the whole system resilient. It also enables sections to have different refresh intervals — a trending keywords section might refresh every minute, while salary insights refresh daily. This is a pattern we see in every successful SDUI implementation.
5. Version-Based Caching Keeps It Fast
The 100-byte version check pattern is elegant and efficient. It proves that SDUI doesn't have to mean "download your entire UI definition on every screen load." Smart caching makes SDUI invisible to the user.
How Pyramid Gives You This Architecture Out of the Box
JobKorea built something impressive — but they also built it from scratch. The admin tool, the Redis caching layer, the version management, the client SDK for parsing and rendering, the fallback logic, the section isolation — all custom code that needs ongoing maintenance.
Pyramid gives you the same architectural pattern as a managed platform:
| Capability | JobKorea (DIY) | Pyramid |
|---|---|---|
| Screen/Section model | Custom implementation | Built-in with visual editor |
| Targeting & segmentation | Custom dimensions | Flexible targeting rules |
| A/B testing | testType field | Built-in experimentation |
| Version-based caching | Custom Redis + client logic | Managed CDN + SDK caching |
| Section isolation | Custom error boundaries | Automatic per-component isolation |
| Fallback logic | Custom fallback config | Declarative fallback chains |
| Native rendering | Custom native components | BYOC — your Compose & SwiftUI components |
| Admin tool | Built internally | Dashboard included |
| Setup time | Months | Days |
Ship UI changes without app releases — like JobKorea, without the DIY
Pyramid gives you Screen/Section architecture, version-based caching, native rendering, and built-in experimentation. All managed.
Get Early Access →Frequently Asked Questions
What SDUI architecture does JobKorea use?
JobKorea uses a two-tier Screen/Section architecture. Screens are top-level page containers parameterized by siteType (JOBKOREA/ALBAMON), deviceType, screenType, segmentType, and testType. Sections are reusable UI blocks within screens, each with its own renderType and independent API data source.
How does JobKorea handle caching in their SDUI system?
They use version-based caching with timestamp strings like "20260219123045". The client checks the version (~100 bytes) on each screen load and only downloads the full screen configuration when the version changes. This keeps network overhead near zero for the vast majority of screen loads.
How does JobKorea do A/B testing with server-driven UI?
A/B testing is built directly into the Screen definition via a testType field. Different test groups receive entirely different Screen configurations — including different sections, different ordering, and different layouts — without any client-side code changes.
What happens if a section fails to load in JobKorea's SDUI?
Each section loads data independently from its own API endpoint. If one section fails, the rest of the screen renders normally. Sections can also define explicit fallbacks — for example, falling back from a personalized carousel to a simple popular jobs list.
Related Articles
- What is Server-Driven UI? A Complete Guide for Mobile Teams →
- How Nubank Uses SDUI to Ship Features to 115M Customers in Minutes →
- SDUI Architecture Patterns: From Simple to Advanced →
- SDUI Error Handling and Fallback Strategies →
- The SDUI Adoption Playbook for Mobile Teams →
- Why Airbnb, Lyft, and Netflix Use Server-Driven UI →
Source: JobKorea Engineering Blog — Server-Driven UI adoption case study, February 2026