Michiel Mulders Michiel loves the Node.js and Go programming languages. A backend/core blockchain developer and avid writer, he's very passionate about blockchain technology.

Create scalable JavaScript and TypeScript file structures with Destiny

4 min read 1292

Intro to Destiny: Prettier For Creating Scalable JavaScript/TypeScript File Structures

I’ve been using JavaScript and TypeScript in my personal projects for a long time now. Some of my more interesting projects end up accumulating countless new files as they evolve. The number of files increases becomes so unwieldy that I find myself struggling to locate exported functions. Does this sound familiar?

In this tutorial, we’ll show you how to restructure your JavaScript and TypeScript app according to the fractal tree concept using Destiny.

Destiny is an open-source project available on npm that scans folders for file dependencies and places the files in a fractal structure, where they are “destined” to be.

The fractal tree concept

Consider a square. Now put two smaller squares on top of it, such that all three make a triangle in the center. Apply the same process to both smaller squares (and again, and again, depending on the number of files), and you have a fractal tree.

Destiny takes the same approach to structuring files. If a file has a dependency, it is moved to a folder with the same name as the file. It follows the principle that states, “Repeat the unit until all dependencies are structured, one below another.”

Benefits of a fractal file structure

Fractal allows you to:

  • Focus on your code and not worry about the dependencies
  • Manage complex file structures
  • Scale faster
  • Avoid the time-consuming task of restructuring your project manually

When multiple people are working on a single project, it’s sometimes difficult to get on the same page in terms of the file structure. Often, a programmer will simply search for all the dependencies in a project to understand the file structure format. The goal of Destiny is to create a common understanding of the file structure so development teams can work more efficiently together.

Below is the fractal representation of a file structure. index.js is the main file and header.js and footer.js are the dependencies of that main file. Ideally, the dependencies are placed inside a folder named index, which is the same as the main file name.

Fractal Representation of the File Structure

How Destiny works

Destiny scans the selected folder and places files according to their dependencies. It follows the steps outlined below to restructure the dependencies.

  1. Scan the selected folder
  2. Create a directed graph according to how the JavaScript/TypeScript files are imported
  3. Create a fractal representation based on the directed graph
  4. Move the files inside the fractal app structure

To better understand how Destiny works, I created a project that demonstrates the file structure before and after using Destiny.

Structure before using Destiny

├── footer.js

├── header.js

├── index.js

├── loginButton.js

├── nav.js

└── search.js

As you can see, this file structure is a fiasco. No one could possibly understand how the dependencies exist in the project without going through all these files individually.

Now let’s take a look at our project’s dependency graph.

Destiny Dependency Graph

There are multiple dependencies organized in a multilevel hierarchy for our index.js file. header.js and footer.js are dependencies of index.js, and header.js has dependencies of its own.

Now let’s see how Destiny transforms the file structure.

Structure after using Destiny

After creating a fractal structure using Destiny, our project will look as follows. The yellow box represents a folder with its name written inside.

Fractal Structure After Using Destiny

This is how the files should be structured in a fractal manner.

Now let’s see what it looks like after applying Destiny to our project. You can simply traverse the file structure and understand the relationships and dependencies between the different components. For example, the index folder contains both a header and a footer. Furthermore, the header consists of a nav component that contains both a login button and a search bar. Easy, right?

├── index

│ ├── footer.js

│ ├── header

│ │ ├── nav

│ │ │ ├── loginButton.js

│ │ │ └── search.js

│ │ └── nav.js

│ └── header.js

└── index.js

Using Destiny from the CLI

It’s very easy to install and use Destiny in your project. If you use npm, write the following command to install Destiny globally.

npm i -g destiny

If you use yarn, use the following command.

yarn global add destiny

To use Destiny in a folder:

destiny <path to source files>

# example

destiny ./src

If you’re using Destiny in a React project, install Destiny and use the following command to scan all files and folders in your src folder.

npx destiny "src/**/*.*"

The structure has not yet been applied with this command. To do so, you need a write flag to apply the changes. You can either use - w or --write to apply the file structure changes.

npx destiny -w "src/**/*.*"

Shared dependencies

What if there is a certain file that is required for both header.js and footer.js but not index.js?

Destiny counters this problem very easily. A new folder called shared is created under the index folder, generating the /index/shared path. Here, the shared dependencies are located next to the highest dependent file.

Destiny Tree Structure

In the above graph, header.js and footer.js have a dependency named _button.js (placed inside curved brackets). This button.js file must be moved to a new folder under the index folder.

After using Destiny, this is how the file structure should look:

File Structure After Using Destiny

As the graph shows, the fractal structure has been applied by Destiny and files have been placed accordingly.

This is what our folder tree looks like now. Below is the structure of a shared dependency project.

├── index

│ ├── footer.js

│ ├── header.js

│ └── shared

│ └── button.js

└── index.js

Other popular file structures

There are many other file structure formats out there, including:

  • Model-view-controller (MVC)
  • Organize by functionality
  • Organize by type

The MVC pattern

The MVC pattern is a classic example of structuring your application. The user interacts with a view and manipulates data in the model via a controller. To close the loop, the model updates the view with the new data, which the user sees again. It’s a popular pattern among popular programming languages such as JavaScript, Python, PHP, Java, and C#.

Organized by functionality

In essence, when you organize by functionality, you organize files according to the functional areas of your application. For example, all functionalities related to handling emails go into an email folder.

You can scale this approach further by grouping more specific functionalities within your higher-level functional folders. For example, let’s say you’re hosting a feature for sending and displaying emails. You can further divide the email folder into a send and receive folder.

Organized by type

When you organize files by type, you get a very similar approach to MVC. A type can be a service, controller, domain, or any other type of file, such as a database model. However, as your application grows, you’re cound to accumulate services. Therefore, when organizing by type, you’ll end up organizing by feature within your type folders to keep your file structure clean.


Destiny was created by developer Ben Awad to manage a file structure for React applications. In the beginning, the tool was called butter-CLI before being changed to Destiny.

In most cases, when a developer starts a project, the project is tidy and well-structured — all files and folders are in their correct place and dependencies are managed properly. But as time passes, it becomes a much bigger effort to keep your file structure clean and tidy. You might move functionalities between components and create many shared folders. Often, you’ll end up with a whirlpool of files and their shared dependencies.

Destiny is designed to help you manage files on a large scale and make the file structure easy to understand for other developers working on your project. As of this writing, Destiny has a solid following with more than 2.7k stars on GitHub and 16 contributors.

: Full visibility into your web and mobile apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page and mobile apps.

: Debug JavaScript errors more easily by understanding the context

Debugging code is always a tedious task. But the more you understand your errors the easier it is to fix them.

LogRocket allows you to understand these errors in new and unique ways. Our frontend monitoring solution tracks user engagement with your JavaScript frontends to give you the ability to find out exactly what the user did that led to an error.

LogRocket records console logs, page load times, stacktraces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier!

Michiel Mulders Michiel loves the Node.js and Go programming languages. A backend/core blockchain developer and avid writer, he's very passionate about blockchain technology.

Leave a Reply