<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Arjun</title>
    <description>The latest articles on DEV Community by Arjun (@arjunsanthosh).</description>
    <link>https://dev.to/arjunsanthosh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F764614%2F9650513f-f9a4-46a5-82d0-adbbab94891f.jpg</url>
      <title>DEV Community: Arjun</title>
      <link>https://dev.to/arjunsanthosh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/arjunsanthosh"/>
    <language>en</language>
    <item>
      <title>Mastering Feature-Sliced Design: Lessons from Real Projects</title>
      <dc:creator>Arjun</dc:creator>
      <pubDate>Mon, 03 Nov 2025 21:11:50 +0000</pubDate>
      <link>https://dev.to/arjunsanthosh/mastering-feature-sliced-design-lessons-from-real-projects-2ida</link>
      <guid>https://dev.to/arjunsanthosh/mastering-feature-sliced-design-lessons-from-real-projects-2ida</guid>
      <description>&lt;h2&gt;
  
  
  🌱 Intro
&lt;/h2&gt;

&lt;p&gt;When building complex front-end applications, architecture decisions can make or break your project’s scalability. One approach that truly stood out to me after working on multiple React projects is &lt;strong&gt;Feature-Sliced Design (FSD)&lt;/strong&gt; — a structured way to organize frontend code by &lt;em&gt;features&lt;/em&gt; and &lt;em&gt;business logic&lt;/em&gt;, not by file types.  &lt;/p&gt;

&lt;p&gt;After implementing FSD in production, I’ve seen how it can bring incredible clarity to large projects — but also how it can slow down smaller ones. This post breaks down my experience, what worked, what didn’t, and where I believe FSD really shines.  &lt;/p&gt;




&lt;h2&gt;
  
  
  🧩 What Is Feature-Sliced Design?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://feature-sliced.design/" rel="noopener noreferrer"&gt;Feature-Sliced Design&lt;/a&gt; (FSD) is an architectural methodology that helps organize frontend projects around &lt;strong&gt;business capabilities&lt;/strong&gt; rather than UI elements or utilities.  &lt;/p&gt;

&lt;p&gt;Instead of grouping files like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
├── components/
├── hooks/
├── pages/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;FSD promotes a more domain-driven structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
├── app/
├── pages/
├── widgets/
├── features/
├── entities/
├── shared/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each layer represents a specific level of abstraction:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;App&lt;/strong&gt; → Application-level setup (providers, routing, config).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pages&lt;/strong&gt; → Route-level compositions.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Widgets&lt;/strong&gt; → Complex UI blocks.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Features&lt;/strong&gt; → Units of user-facing functionality.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entities&lt;/strong&gt; → Core domain logic or data models.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shared&lt;/strong&gt; → Common utilities and base components.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This hierarchy enforces direction — higher layers (like pages) can depend on lower layers (like entities), but not the other way around.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ How It Works in Practice
&lt;/h2&gt;

&lt;p&gt;Let’s imagine a &lt;strong&gt;Fintech Dashboard&lt;/strong&gt; — something similar to Revolut or Wise.&lt;br&gt;&lt;br&gt;
Using FSD, you might structure it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
 ├─ app/
 │   └─ providers/
 │       ├─ AuthProvider.tsx
 │       └─ ThemeProvider.tsx
 ├─ pages/
 │   ├─ home/
 │   ├─ transactions/
 │   └─ payments/
 ├─ widgets/
 │   ├─ account-summary/
 │   └─ transaction-table/
 ├─ features/
 │   ├─ filter-transactions/
 │   ├─ make-payment/
 │   └─ export-statement/
 ├─ entities/
 │   ├─ user/
 │   └─ transaction/
 └─ shared/
     ├─ ui/
     ├─ api/
     └─ lib/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s what each layer does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;app/&lt;/strong&gt; – Setup code like providers and routing.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pages/&lt;/strong&gt; – Entry points connected to routes.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;widgets/&lt;/strong&gt; – Complex UI blocks composed of multiple features or entities.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;features/&lt;/strong&gt; – User-driven actions (e.g., filtering, exporting).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;entities/&lt;/strong&gt; – Domain models like User, Account, or Transaction.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;shared/&lt;/strong&gt; – Reusable utilities, UI components, and constants.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💡 My Experience Using FSD
&lt;/h2&gt;

&lt;p&gt;In one of my recent React + Next.js projects, I used FSD to manage a &lt;strong&gt;financial transaction portal&lt;/strong&gt; with multiple teams contributing to different modules.&lt;br&gt;&lt;br&gt;
Before adopting FSD, we constantly ran into issues like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unclear ownership of modules
&lt;/li&gt;
&lt;li&gt;Duplicated logic across pages
&lt;/li&gt;
&lt;li&gt;Difficulty in reusing UI components
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After restructuring the app with FSD, we saw these &lt;strong&gt;key benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Separation of concerns&lt;/strong&gt; — Teams could work on &lt;code&gt;features/&lt;/code&gt; and &lt;code&gt;entities/&lt;/code&gt; independently.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High reusability&lt;/strong&gt; — Shared logic (like authentication or API clients) became easier to reuse.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Predictable structure&lt;/strong&gt; — Every feature followed the same pattern, which made onboarding new developers faster.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clean imports&lt;/strong&gt; — With proper path aliases, we avoided deep relative imports like &lt;code&gt;../../../Button&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A small but meaningful example:&lt;br&gt;&lt;br&gt;
We moved the “Download Report” feature into its own folder (&lt;code&gt;features/download-report&lt;/code&gt;) — complete with its UI button with dropdown options, generating PDF logic, and hooks. Later, we reused that same feature on many listing pages without duplication. That kind of modularity simply wasn’t possible before.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Why It’s Great for Large Projects
&lt;/h2&gt;

&lt;p&gt;When your project spans multiple domains or teams, FSD helps in three big ways:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Scalability&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Each feature is self-contained — you can add or remove functionality without refactoring other parts.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Parallel Development&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Different teams can safely work in parallel, since features are isolated.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Easy Abstraction&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You can extract features or entities into a &lt;strong&gt;component library&lt;/strong&gt; later with minimal changes.&lt;/p&gt;

&lt;p&gt;For example, a shared &lt;code&gt;auth&lt;/code&gt; module or a &lt;code&gt;user&lt;/code&gt; entity can later be moved into an internal library for reuse across microfrontends.&lt;/p&gt;

&lt;p&gt;📗 Read more: &lt;a href="https://feature-sliced.design/docs/reference/layers" rel="noopener noreferrer"&gt;Understanding Layers in FSD&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 Why I Found FSD Valuable in Large Projects
&lt;/h2&gt;

&lt;p&gt;In one of my SaaS projects, we had multiple independent modules — Dashboard, Listing Page (with features like filtering and exporting), and Reports. Each module had its own logic, UI, and state management.&lt;/p&gt;

&lt;p&gt;By applying FSD, each feature became a self-contained slice with clear boundaries. This had huge benefits:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developers could work independently without touching unrelated parts of the codebase.
&lt;/li&gt;
&lt;li&gt;Each feature could later be published as a standalone package or reused in another project.
&lt;/li&gt;
&lt;li&gt;Refactoring became predictable — no mysterious side effects.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;level of reusability and modularity&lt;/strong&gt; we achieved was far better than any flat folder structure could offer.  &lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Challenges and Real-World Lessons
&lt;/h2&gt;

&lt;p&gt;While FSD works beautifully at scale, applying it effectively requires discipline and experience. Here are some lessons I learned along the way:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Defining Feature Boundaries Is Hard
&lt;/h3&gt;

&lt;p&gt;The hardest part of FSD is figuring out where one feature ends and another begins. In theory, features should represent user actions like “log in” or “view reports.” But in practice, things like &lt;strong&gt;authentication&lt;/strong&gt;, &lt;strong&gt;permissions&lt;/strong&gt;, or &lt;strong&gt;logging&lt;/strong&gt; don’t fit neatly into any one feature.  &lt;/p&gt;

&lt;p&gt;I learned to treat such &lt;em&gt;cross-cutting concerns&lt;/em&gt; as infrastructure or shared context, not as individual features. This helps keep feature slices clean and focused.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Over-Slicing Early Is a Trap
&lt;/h3&gt;

&lt;p&gt;Early in my FSD journey, I tried slicing everything — even small UI interactions. That quickly became unmanageable. Many slices were too small to justify their existence, and navigating the file tree became a chore.  &lt;/p&gt;

&lt;p&gt;The better approach was to start simple and &lt;strong&gt;slice only when the need arises&lt;/strong&gt;. When a piece of functionality grows enough to deserve isolation, that’s when it becomes a feature.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Grouping Related Features Works — With Caution
&lt;/h3&gt;

&lt;p&gt;For larger domains like Authentication, grouping sub-features (login, signup, reset password) made sense. But I also learned that &lt;strong&gt;grouping can blur boundaries&lt;/strong&gt; if not carefully managed.  &lt;/p&gt;

&lt;p&gt;When a sub-feature grows beyond its parent domain, it’s often better to promote it into a standalone feature. Trying to over-organize can sometimes cause more friction than it solves.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. The “Shared” Layer Can Become a Dumping Ground
&lt;/h3&gt;

&lt;p&gt;Every team I’ve worked with eventually faces the same issue: the &lt;code&gt;shared/&lt;/code&gt; folder starts to collect everything. It’s easy to fall into the trap of putting unrelated utilities or UI elements there.  &lt;/p&gt;

&lt;p&gt;To avoid this, I adopted a simple rule — if it’s not reusable in &lt;em&gt;multiple independent contexts&lt;/em&gt;, it doesn’t belong in &lt;code&gt;shared/&lt;/code&gt;. That discipline helps prevent the “shared mess” problem that many large teams encounter.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. It’s Not for Every Project Size
&lt;/h3&gt;

&lt;p&gt;For small apps or prototypes, FSD is simply too much. Setting up layers and enforcing boundaries adds unnecessary boilerplate when your app only has a few pages.  &lt;/p&gt;

&lt;p&gt;I now apply FSD only when I know the project will grow — typically when working on SaaS platforms, dashboards, or modular systems. For smaller side projects, a simpler structure like &lt;a href="https://github.com/alan2207/bulletproof-react" rel="noopener noreferrer"&gt;Bulletproof React&lt;/a&gt; works perfectly.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 Practical Tips That Worked for Me
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Introduce FSD gradually&lt;/strong&gt; — don’t restructure everything at once.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep feature definitions narrow&lt;/strong&gt; — one clear responsibility per slice.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use lint rules&lt;/strong&gt; like &lt;a href="https://www.npmjs.com/package/eslint-plugin-boundaries" rel="noopener noreferrer"&gt;eslint-plugin-boundaries&lt;/a&gt; to enforce import order.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document the structure&lt;/strong&gt; so the entire team follows the same conventions.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep shared minimal&lt;/strong&gt; — it should serve the app, not own it.
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🚀 My Takeaway
&lt;/h2&gt;

&lt;p&gt;Feature-Sliced Design is one of the most effective architectures I’ve used for scaling front-end projects. It encourages separation of concerns, reusability, and parallel development. However, it’s not a silver bullet.  &lt;/p&gt;

&lt;p&gt;In my experience:&lt;br&gt;&lt;br&gt;
✅ It excels in &lt;strong&gt;large, domain-heavy&lt;/strong&gt; projects.&lt;br&gt;&lt;br&gt;
❌ It feels heavy-handed and slow in &lt;strong&gt;smaller applications&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;If you expect your app to grow, FSD gives you a foundation that’s easy to maintain, scale, and evolve. If not, you might just be over-engineering the problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  📚 Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Official documentation: &lt;a href="https://feature-sliced.design/" rel="noopener noreferrer"&gt;https://feature-sliced.design/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;ESLint boundaries plugin: &lt;a href="https://www.npmjs.com/package/eslint-plugin-boundaries" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/eslint-plugin-boundaries&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




</description>
      <category>architecture</category>
      <category>frontend</category>
      <category>react</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Building Our Own `create-app` CLI — A Custom NPX Script for Fast Project Bootstrapping</title>
      <dc:creator>Arjun</dc:creator>
      <pubDate>Fri, 31 Oct 2025 20:18:20 +0000</pubDate>
      <link>https://dev.to/arjunsanthosh/building-our-own-create-app-cli-a-custom-npx-script-for-fast-project-bootstrapping-18l8</link>
      <guid>https://dev.to/arjunsanthosh/building-our-own-create-app-cli-a-custom-npx-script-for-fast-project-bootstrapping-18l8</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;When our team began building multiple web applications using &lt;strong&gt;Next.js&lt;/strong&gt;, we didn’t initially think about creating a CLI tool. We just wanted to ship products fast and maintain a consistent development experience across projects. But as the number of products grew, we realized that setting up each new application from scratch was repetitive, time-consuming, and error-prone.&lt;/p&gt;

&lt;p&gt;This is the story of how we built our own &lt;strong&gt;custom &lt;code&gt;npx&lt;/code&gt; script&lt;/strong&gt;, inspired by tools like &lt;code&gt;create-next-app&lt;/code&gt;, to help our developers spin up new projects instantly — complete with our in-house configurations, libraries, and folder structure.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Beginning: From One App to Many
&lt;/h2&gt;

&lt;p&gt;It started with one app.&lt;br&gt;&lt;br&gt;
Then came another.&lt;br&gt;&lt;br&gt;
And soon, several more.&lt;/p&gt;

&lt;p&gt;Our frontend team was responsible for building multiple product UIs for different internal and customer-facing tools. We were using &lt;strong&gt;Next.js&lt;/strong&gt; as our primary framework, following the &lt;a href="https://feature-sliced.design/" rel="noopener noreferrer"&gt;&lt;strong&gt;Feature-Sliced Design (FSD)&lt;/strong&gt;&lt;/a&gt; methodology — an architectural pattern that helps organize frontend projects into clear, maintainable layers.&lt;/p&gt;

&lt;p&gt;Each new app required:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Installing common dependencies (like our in-house component and utility libraries).
&lt;/li&gt;
&lt;li&gt;Setting up authentication logic.
&lt;/li&gt;
&lt;li&gt;Maintaining a consistent folder structure (based on FSD).
&lt;/li&gt;
&lt;li&gt;Applying our own &lt;strong&gt;ESLint&lt;/strong&gt;, &lt;strong&gt;Prettier&lt;/strong&gt;, and &lt;strong&gt;Husky&lt;/strong&gt; configurations.
&lt;/li&gt;
&lt;li&gt;Enforcing a consistent code style and commit rules across repositories.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After a few projects, we realized we were spending too much time doing setup work that could easily be automated.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Starter Template
&lt;/h2&gt;

&lt;p&gt;So we created a &lt;strong&gt;starter template&lt;/strong&gt; — a cleaned-up, minimal Next.js app that included all our standard configurations and base dependencies.&lt;/p&gt;

&lt;p&gt;It served as a “bare minimum” project — something new developers could clone and start coding right away. The template included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Next.js setup with TypeScript
&lt;/li&gt;
&lt;li&gt;✅ Pre-configured ESLint, Prettier, and Husky
&lt;/li&gt;
&lt;li&gt;✅ Authentication boilerplate
&lt;/li&gt;
&lt;li&gt;✅ FSD folder structure (&lt;code&gt;src/app&lt;/code&gt;, &lt;code&gt;src/entities&lt;/code&gt;, &lt;code&gt;src/features&lt;/code&gt;, etc.)
&lt;/li&gt;
&lt;li&gt;✅ In-house component and utility libraries
&lt;/li&gt;
&lt;li&gt;✅ Git hooks for linting and formatting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This helped us a lot initially. But soon, as more developers joined and new types of projects emerged (like &lt;strong&gt;prototype apps&lt;/strong&gt; to test UI designs quickly), managing multiple starter templates manually became difficult.&lt;/p&gt;

&lt;p&gt;That’s when we decided to take it one step further.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Idea: A Custom &lt;code&gt;npx&lt;/code&gt; Script Like &lt;a href="https://github.com/vercel/next.js/tree/canary/packages/create-next-app" rel="noopener noreferrer"&gt;&lt;code&gt;create-next-app&lt;/code&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;We wanted to give our developers a simple command like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-our-app my-new-project &lt;span class="nt"&gt;--template&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;starter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or for prototype apps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-our-app my-proto-project &lt;span class="nt"&gt;--template&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;proto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal was to automate:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creating a new project directory.
&lt;/li&gt;
&lt;li&gt;Copying the correct template files.
&lt;/li&gt;
&lt;li&gt;Installing dependencies.
&lt;/li&gt;
&lt;li&gt;Setting up git, linting, and formatting.
&lt;/li&gt;
&lt;li&gt;Applying our team’s coding standards automatically.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Essentially, we wanted something that felt like &lt;strong&gt;&lt;code&gt;create-next-app&lt;/code&gt;&lt;/strong&gt;, but fully tailored to our ecosystem.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Technical Implementation
&lt;/h2&gt;

&lt;p&gt;We took inspiration from &lt;strong&gt;Vercel’s &lt;code&gt;create-next-app&lt;/code&gt;&lt;/strong&gt; repository. It’s a great reference for building custom NPX tools, and its structure made a lot of sense.&lt;/p&gt;

&lt;p&gt;Our project followed a similar layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;create-our-app/
├── templates/
│   ├── starter/
│   ├── proto/
│   └── common/
├── src/
│   ├── helpers/
│   │   ├── downloadTemplate.ts
│   │   ├── copyTemplateFiles.ts
│   │   ├── installDependencies.ts
│   │   └── log.ts
│   └── index.ts
├── package.json
└── tsconfig.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;&lt;code&gt;index.ts&lt;/code&gt;&lt;/strong&gt; file serves as the entry point — it handles argument parsing, project name validation, and calls helper functions for each setup step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up package.json for a CLI Tool
&lt;/h3&gt;

&lt;p&gt;To make your CLI runnable with npx or after a global install, you need to configure the bin field in your package.json.&lt;br&gt;
This field tells Node.js which file to execute when the command is called.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;Example:&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"create-our-app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A custom NPX script to bootstrap frontend projects with our starter templates"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"create-our-app"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dist/index.js"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"files"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"dist"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"repository"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"git"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/our-org/create-our-app.git"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Your Team Name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"license"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MIT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"commander"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^11.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"inquirer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^9.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"fs-extra"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^11.1.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tar"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^6.2.0"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explanation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;bin&lt;/strong&gt; — maps your command name (create-our-app) to the executable file (after it’s built, e.g., &lt;code&gt;dist/index.js&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;type&lt;/strong&gt; — ensures Node treats your project as an ES module (if using ES imports).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;files&lt;/strong&gt; — limits which files are published to npm (here, only dist).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;repository&lt;/strong&gt; — links the CLI’s GitHub repo for transparency and easy access.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once this is set up and you’ve built your project, you can test it locally with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;link&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can run your CLI globally using:&lt;/p&gt;

&lt;p&gt;create-our-app my-app&lt;/p&gt;

&lt;h3&gt;
  
  
  Argument Parsing
&lt;/h3&gt;

&lt;p&gt;We used the &lt;a href="https://www.npmjs.com/package/commander" rel="noopener noreferrer"&gt;&lt;code&gt;commander&lt;/code&gt;&lt;/a&gt; library for parsing CLI arguments. It made it easy to handle flags like &lt;code&gt;--template&lt;/code&gt;, &lt;code&gt;--use-npm&lt;/code&gt;, or &lt;code&gt;--git&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Command&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;commander&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;program&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;program&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;create-our-app&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Initialize a new frontend project with our custom setup&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-t, --template &amp;lt;template&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Choose a template&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;starter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--use-npm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Use npm instead of yarn&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Interactive Prompts with Inquirer
&lt;/h3&gt;

&lt;p&gt;We also integrated &lt;a href="https://www.npmjs.com/package/inquirer" rel="noopener noreferrer"&gt;&lt;code&gt;inquirer&lt;/code&gt;&lt;/a&gt; to make the CLI interactive.&lt;br&gt;&lt;br&gt;
If a user skips the CLI arguments (like template name or package manager), the script automatically prompts them with questions.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;inquirer&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;inquirer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;answers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;inquirer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;list&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;template&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Choose a project template:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;starter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;proto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;starter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;list&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pkgManager&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Select a package manager:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;npm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;yarn&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pnpm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;npm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Downloading Templates
&lt;/h3&gt;

&lt;p&gt;For flexibility, we wanted developers to pass a &lt;strong&gt;GitHub URL&lt;/strong&gt; instead of just using built-in templates.&lt;br&gt;&lt;br&gt;
For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-our-app my-app &lt;span class="nt"&gt;--template&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://github.com/our-org/custom-template
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To achieve that, we used &lt;strong&gt;tarball downloads&lt;/strong&gt; from GitHub’s codeload API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://codeload.github.com/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/tar.gz/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;branch&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We then extracted the tar file using the &lt;a href="https://www.npmjs.com/package/tar" rel="noopener noreferrer"&gt;&lt;code&gt;tar&lt;/code&gt;&lt;/a&gt; package, which let us clone only the needed files instead of pulling the entire Git history.&lt;/p&gt;

&lt;h3&gt;
  
  
  Copying Local Templates
&lt;/h3&gt;

&lt;p&gt;If a local template was used, we relied on &lt;a href="https://www.npmjs.com/package/fs-extra" rel="noopener noreferrer"&gt;&lt;code&gt;fs-extra&lt;/code&gt;&lt;/a&gt; for copying directories recursively. This library also helped us handle file overwrites and cleanups safely.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fs-extra&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`../templates/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;targetDirectory&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Installing Dependencies
&lt;/h3&gt;

&lt;p&gt;After copying the template, the script automatically installed dependencies using either npm, yarn, or pnpm — depending on what the developer preferred or had installed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;execSync&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;child_process&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;execSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pkgManager&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; install`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;stdio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;inherit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Result: Developer Happiness 😄
&lt;/h2&gt;

&lt;p&gt;After introducing our custom CLI, onboarding new developers became seamless.&lt;/p&gt;

&lt;p&gt;Instead of sharing long setup instructions, we just gave them a single command. Within a couple of minutes, they had a fully configured Next.js project with all our defaults in place.&lt;/p&gt;

&lt;p&gt;Some key benefits we noticed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⚡ &lt;strong&gt;Faster onboarding&lt;/strong&gt; — No more copy-pasting config files.
&lt;/li&gt;
&lt;li&gt;🔒 &lt;strong&gt;Consistency&lt;/strong&gt; — Every project follows the same structure and rules.
&lt;/li&gt;
&lt;li&gt;🧩 &lt;strong&gt;Scalability&lt;/strong&gt; — Adding new templates (e.g., mobile dashboard, prototype app) is easy.
&lt;/li&gt;
&lt;li&gt;🔧 &lt;strong&gt;Maintainability&lt;/strong&gt; — Centralized control over shared tooling and updates.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;p&gt;A few things we learned while building this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start simple — the first version doesn’t need every feature.
&lt;/li&gt;
&lt;li&gt;Document every flag and template — new developers will thank you later.
&lt;/li&gt;
&lt;li&gt;Avoid making assumptions about the environment (e.g., which package manager is installed).
&lt;/li&gt;
&lt;li&gt;Use meaningful logs and color-coded output for better CLI UX (we used &lt;code&gt;chalk&lt;/code&gt; for this).
&lt;/li&gt;
&lt;li&gt;Always clean up temporary files and handle errors gracefully.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What’s Next
&lt;/h2&gt;

&lt;p&gt;We’re planning to add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More interactive prompts for optional modules (like auth, analytics, or feature toggles).
&lt;/li&gt;
&lt;li&gt;Remote template versioning for better maintainability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The journey of building this tool taught us that &lt;strong&gt;developer experience (DX)&lt;/strong&gt; is as important as user experience. By investing a bit of time in tooling, we saved countless hours for our team and made development far more consistent and enjoyable.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;In short:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Our custom &lt;code&gt;npx&lt;/code&gt; script started as a small internal experiment but quickly became one of the most impactful productivity tools in our development workflow.&lt;/p&gt;

</description>
      <category>npx</category>
      <category>nextjs</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Custom Build folder for React</title>
      <dc:creator>Arjun</dc:creator>
      <pubDate>Fri, 24 Dec 2021 23:48:56 +0000</pubDate>
      <link>https://dev.to/arjunsanthosh/custom-build-folder-for-react-2oi</link>
      <guid>https://dev.to/arjunsanthosh/custom-build-folder-for-react-2oi</guid>
      <description>&lt;h1&gt;
  
  
  🧱 How to Change the Build Path in a React Application
&lt;/h1&gt;

&lt;p&gt;Sometimes you may want your React app’s build output to be moved to a different directory — for example, into a server’s &lt;code&gt;public&lt;/code&gt; folder. In this guide, we’ll see how to do that using a simple shell script that runs automatically after the build process.&lt;/p&gt;




&lt;h2&gt;
  
  
  🪶 Step 1: Create a Shell Script
&lt;/h2&gt;

&lt;p&gt;Create a new shell script file named &lt;strong&gt;&lt;code&gt;{file-name}.sh&lt;/code&gt;&lt;/strong&gt; inside the &lt;strong&gt;root directory&lt;/strong&gt; of your React project.&lt;/p&gt;




&lt;h2&gt;
  
  
  🪶 Step 2: Update &lt;code&gt;package.json&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Open your &lt;strong&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/strong&gt; file and add a new script named &lt;strong&gt;&lt;code&gt;postbuild&lt;/code&gt;&lt;/strong&gt; right below the existing build script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"react-scripts start"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"react-scripts build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"postbuild"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./{file-name}.sh"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Note:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If you’re on &lt;strong&gt;Windows&lt;/strong&gt;, make sure you have &lt;strong&gt;Git Bash&lt;/strong&gt; or &lt;strong&gt;WSL&lt;/strong&gt; installed to run the script, since native Command Prompt doesn’t support bash syntax.&lt;br&gt;&lt;br&gt;
You can run it manually using:&lt;br&gt;&lt;br&gt;
&lt;code&gt;bash {file-name}.sh&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6wu9ivyubo0hd3p1osbl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6wu9ivyubo0hd3p1osbl.png" alt=" " width="416" height="173"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🪶 Step 3: Write the Shell Script
&lt;/h2&gt;

&lt;p&gt;The shell script will move your built files to a new directory after every build.&lt;br&gt;&lt;br&gt;
Here’s a sample script you can modify as needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="c"&gt;# Define your app name or set it as an environment variable&lt;/span&gt;
&lt;span class="nv"&gt;APP_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"my-react-app"&lt;/span&gt;

&lt;span class="c"&gt;# If the target folder exists, remove its contents first, then move the new files&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"./../server/public/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;APP_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Target folder exists. Cleaning it..."&lt;/span&gt;
    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rv&lt;/span&gt; ./../server/public/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;APP_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;
    &lt;span class="c"&gt;# Move the build files (use cp -r instead of mv if you want to keep a copy)&lt;/span&gt;
    &lt;span class="nb"&gt;mv&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; build/&lt;span class="k"&gt;*&lt;/span&gt; ./../server/public/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;APP_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/
&lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="c"&gt;# Otherwise, create the target folder and then move the files&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Creating target folder and moving files..."&lt;/span&gt;
    &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ./../server/public/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;APP_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
    &lt;span class="nb"&gt;mv&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; build/&lt;span class="k"&gt;*&lt;/span&gt; ./../server/public/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;APP_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;🧩 &lt;strong&gt;Tip:&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;mv&lt;/code&gt; moves the files (the &lt;code&gt;build&lt;/code&gt; folder will be emptied afterward).
&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;cp -r&lt;/code&gt; instead if you prefer to copy the files and keep the original &lt;code&gt;build&lt;/code&gt; intact.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🧩 How It Works
&lt;/h2&gt;

&lt;p&gt;When you run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;React completes its build process and then automatically executes the &lt;strong&gt;&lt;code&gt;postbuild&lt;/code&gt;&lt;/strong&gt; script.&lt;br&gt;&lt;br&gt;
This script checks if the target directory already exists:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ If it exists — the folder is cleared, and new build files are moved in.
&lt;/li&gt;
&lt;li&gt;🆕 If not — it creates the folder and moves the files.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Make sure your project structure matches this example:  &lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/my-project
├── react-app/
└── server/
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Adjust the relative path (&lt;code&gt;./../server/public/&lt;/code&gt;) if your setup differs.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🧠 Customize It
&lt;/h2&gt;

&lt;p&gt;You can tweak this script for your own directory structure or workflow.&lt;br&gt;&lt;br&gt;
To explore more possibilities, check out a few beginner-friendly shell scripting tutorials — you’ll be surprised how much you can automate.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎉 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;That’s it! With this small setup, your React app’s build files will automatically be relocated right after each build — no manual steps needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Happy Coding! 🥳&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>bash</category>
    </item>
  </channel>
</rss>
