











{"author":"Faiq Najib Al-Aziz","body":"\nThe move from [episode one](/en/writing/2026/hijrah-frontend-01/) is finally done. On handover day, the manifest had just one important number: **seventy-six boxes in, seventy-six boxes out. Not a single page left behind.**\n\nNothing got left behind because that's what we decided. Some things were brought on purpose, some boarded without an invitation, and one big plan was dropped in the end. Let me tell you one by one.\n\n## Why Zero Pages Were Left Behind\n\nIf you've ever moved house, you know the relief of saying, \"just throw this one away\". A frontend migration has the same temptation. Deleting a page feels like tidying up the product while you're at it.\n\nThe catch: deciding whether a page lives or dies during a move means making two decisions at once, migrating the app and changing the product's scope. [The neighboring series](/en/writing/2026/hijrah-backend-04/) already taught me how expensive that combination is. So the rule was clear: **seventy-six in, seventy-six out**, checked page by page, with no script for throwing things away.\n\nThe result isn't dramatic, but the numbers match: the new repo has 76 pages, same as the old one, and the folder lists line up one by one. Pages with names that make you wonder, like demo, docs, and special-purpose routes, came along too. Not because every one of them matters, but because deciding to delete them wasn't part of this phase.\n\n## The First Boxes I Opened\n\nThe first boxes I opened held the two UI libraries that have lived side by side for a long time. In the new house, the count is easy to see: one library appears in **101 files**, while the other survives in just **13 files**.[^1]\n\nThe numbers show two eras: one library dominated, the other arrived later, and both live in the same app without open warfare. We brought both. Removing a library means changing every file that imports it, and changing every file during a move breaks the rules from [episode four](/en/writing/2026/hijrah-backend-04/).\n\nThe legacy state management connection came along too. Only one connection point is left in the new app router, but it's still the heart of the pages that use it. Cutting it now means changing something else again, and that's not this move's job.\n\n## Carried Knowingly, Written Down\n\nA few smaller pieces of inheritance also got noted as they boarded:\n\n- **JSX without types**: this country doesn't speak _TypeScript_ yet. Not this episode's decision, just noted for another decision on another day.[^2]\n- **Two eras of naming**: some names start with capital letters, others follow a different taste. We didn't standardize during the move. Standardizing is the epilogue's job, not the suitcase's.\n- **One `page.backup`**: one page brought along its own backup corpse. I laughed when I found it, because [it has a sibling](/en/writing/2026/hijrah-backend-04/) in the building next door hahaha.\n\nThere's a difference between bringing something knowingly and discovering it after the move. The first has a note, a reason, and a turn for cleanup later. The second is easy to miss, and then it multiplies.\n\n## The Big Plan That Didn't Happen\n\nLike in the neighboring series, there's one plan worth recording even though it never ran: replacing the legacy state management with a new one.\n\nIt wasn't dropped because it failed. Priorities shifted toward work users would feel more. Calling off a plan before it eats your energy is a kind of _quality control_ for your own plans. Well... let's call it that hehe.\n\n## Takeaways\n\n1. **Move 1:1 first, decide scope later.** Deleting pages during a move means two decisions at once.\n2. **Count what's in the boxes.** The 76-to-76 and 101-to-13 numbers make the inheritance concrete, not just a matter of taste.\n3. **Two libraries living together mark two different eras.** Each has its own reason for still being in the app.\n4. **A plan canceled before it burns resources is also a good decision.** Write down why, so it's clear when to revisit it.\n\nThe next box doesn't contain a library, but inconsistent data types: the same field sent as a number, an empty string, or a plain string depending on the page. That's where the _type chaos_ starts to show.\n\n[^1]: File, page, and library usage figures were measured directly from the repo as this episode was written, with internal details separated out for storytelling.\n\n[^2]: Library, framework, and folder structure names are kept just enough; whatever the story doesn't need goes unmentioned.\n","body_clean":"The move from episode one is finally done. On handover day, the manifest had just one important number: seventy-six boxes in, seventy-six boxes out. Not a single page left behind.\nNothing got left behind because that\u0026rsquo;s what we decided. Some things were brought on purpose, some boarded without an invitation, and one big plan was dropped in the end. Let me tell you one by one.\nWhy Zero Pages Were Left Behind #If you\u0026rsquo;ve ever moved house, you know the relief of saying, \u0026ldquo;just throw this one away\u0026rdquo;. A frontend migration has the same temptation. Deleting a page feels like tidying up the product while you\u0026rsquo;re at it.\nThe catch: deciding whether a page lives or dies during a move means making two decisions at once, migrating the app and changing the product\u0026rsquo;s scope. The neighboring series already taught me how expensive that combination is. So the rule was clear: seventy-six in, seventy-six out, checked page by page, with no script for throwing things away.\nThe result isn\u0026rsquo;t dramatic, but the numbers match: the new repo has 76 pages, same as the old one, and the folder lists line up one by one. Pages with names that make you wonder, like demo, docs, and special-purpose routes, came along too. Not because every one of them matters, but because deciding to delete them wasn\u0026rsquo;t part of this phase.\nThe First Boxes I Opened #The first boxes I opened held the two UI libraries that have lived side by side for a long time. In the new house, the count is easy to see: one library appears in 101 files, while the other survives in just 13 files.1\nThe numbers show two eras: one library dominated, the other arrived later, and both live in the same app without open warfare. We brought both. Removing a library means changing every file that imports it, and changing every file during a move breaks the rules from episode four.\nThe legacy state management connection came along too. Only one connection point is left in the new app router, but it\u0026rsquo;s still the heart of the pages that use it. Cutting it now means changing something else again, and that\u0026rsquo;s not this move\u0026rsquo;s job.\nCarried Knowingly, Written Down #A few smaller pieces of inheritance also got noted as they boarded:\nJSX without types: this country doesn\u0026rsquo;t speak TypeScript yet. Not this episode\u0026rsquo;s decision, just noted for another decision on another day.2 Two eras of naming: some names start with capital letters, others follow a different taste. We didn\u0026rsquo;t standardize during the move. Standardizing is the epilogue\u0026rsquo;s job, not the suitcase\u0026rsquo;s. One page.backup: one page brought along its own backup corpse. I laughed when I found it, because it has a sibling in the building next door hahaha. There\u0026rsquo;s a difference between bringing something knowingly and discovering it after the move. The first has a note, a reason, and a turn for cleanup later. The second is easy to miss, and then it multiplies.\nThe Big Plan That Didn\u0026rsquo;t Happen #Like in the neighboring series, there\u0026rsquo;s one plan worth recording even though it never ran: replacing the legacy state management with a new one.\nIt wasn\u0026rsquo;t dropped because it failed. Priorities shifted toward work users would feel more. Calling off a plan before it eats your energy is a kind of quality control for your own plans. Well\u0026hellip; let\u0026rsquo;s call it that hehe.\nTakeaways # Move 1:1 first, decide scope later. Deleting pages during a move means two decisions at once. Count what\u0026rsquo;s in the boxes. The 76-to-76 and 101-to-13 numbers make the inheritance concrete, not just a matter of taste. Two libraries living together mark two different eras. Each has its own reason for still being in the app. A plan canceled before it burns resources is also a good decision. Write down why, so it\u0026rsquo;s clear when to revisit it. The next box doesn\u0026rsquo;t contain a library, but inconsistent data types: the same field sent as a number, an empty string, or a plain string depending on the page. That\u0026rsquo;s where the type chaos starts to show.\nFile, page, and library usage figures were measured directly from the repo as this episode was written, with internal details separated out for storytelling.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nLibrary, framework, and folder structure names are kept just enough; whatever the story doesn\u0026rsquo;t need goes unmentioned.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","canonical":"https://najib.id/en/writing/2026/hijrah-frontend-02/","description":"Episode 2 of the Hijrah Frontend series: 76 pages in, 76 pages out. Why nothing got left behind, what was in the first boxes I opened, and one big plan that never happened.","language":"en","lastmod":"2026-10-29T09:31:17Z","publishedAt":"2026-09-23T09:00:02Z","readingTime":4,"section":"writing","series":"Hijrah Frontend","tags":["frontend","nextjs","migration","story"],"title":"Hijrah Frontend (2): The Thin Port and the Inheritance That Boarded","type":"writing","url":"https://najib.id/en/writing/2026/hijrah-frontend-02/","wordCount":723}
