apps/docs/content/docs/crafting-your-repository/creating-an-internal-package.mdx
Internal Packages are the building blocks of your workspace, giving you a powerful way to share code and functionality across your repo. Turborepo automatically understands the relationships between Internal Packages using the dependencies in package.json, creating a Package Graph under the hood to optimize your repository's workflows.
Let's create your first Internal Package to share math utilities in your repo using the guidance in the Anatomy of a package section and the Compiled Packages pattern. In the steps below, we assume you've created a new repository using create-turbo or are using a similarly structured repository.
You'll need a directory to put the package in. Let's create one at ./packages/math.
Next, create the package.json for the package. By adding this file, you'll fulfill the two requirements for an Internal Package, making it discoverable to Turborepo and the rest of your Workspace.
Let's break down this package.json piece-by-piece:
name: This is the most critical field for package discoverability. The value @repo/math becomes the exact identifier used in import statements throughout your workspace. If you change this name, you must update all import statements accordingly.scripts: The dev and build script compile the package using the TypeScript compiler. The dev script will watch for changes to source code and automatically recompile the package.devDependencies: typescript and @repo/typescript-config are devDependencies so you can use those packages in the @repo/math package. In a real-world package, you will likely have more devDependencies and dependencies - but we can keep it simple for now.exports: Defines multiple entrypoints for the package so it can be used in other packages (import { add } from '@repo/math/add').Notably, this package.json declares an Internal Package, @repo/typescript-config, as a dependency. Turborepo will recognize @repo/math as a dependent of @repo/typescript-config for ordering your tasks.
Specify the TypeScript configuration for this package by adding a tsconfig.json file to the root of the package. TypeScript has an extends key, allowing you to use a base configuration throughout your repository and overwrite with different options as needed.
{
"extends": "@repo/typescript-config/base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
You've done four important things here:
@repo/typescript-config/base.json configuration that lives in ./packages/typescript-config has all the configuration you need so you extend from it.outDir key in compilerOptions tells TypeScript where to put the compiled output. It matches the directory specified in your exports in package.json.rootDir key in compilerOptions ensures that the output in outDir uses the same structure as the src directory.include and exclude keys are not inherited from the base configuration, according to the TypeScript specification, so you've included them here.You can now write some code for your package. Create two files inside a src directory:
<Tabs items={['add.ts', 'subtract.ts']}> <Tab value="add.ts">
```ts title="./packages/math/src/add.ts"
export const add = (a: number, b: number) => a + b;
```
```ts title="./packages/math/src/subtract.ts"
export const subtract = (a: number, b: number) => a - b;
```
These files map to the outputs that will be created by tsc when you run turbo build in a moment.
You're ready to use your new package in an application. Let's add it to the web application.
@repo/math is now available in the web application, you can use it in your code:
import { add } from "@repo/math/add";
function Page() {
return <div>{add(1, 2)}</div>;
}
export default Page;
Add the artifacts for the new @repo/math library to the outputs for the build task in turbo.json. This ensures that its build outputs will be cached by Turborepo, so they can be restored instantly when you start running builds.
// [!code word:"dist/**"]
{
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "!.next/cache/**", "dist/**"]
}
}
}
If you've installed turbo globally, run turbo build in your terminal at the root of your Workspace. You can also run the build script from package.json with your package manager, which will use turbo run build.
The @repo/math package built before the web application built so that the runtime code in ./packages/math/dist is available to the web application when it bundles.
When you're creating Internal Packages, it's recommended to create packages that have a single "purpose". This isn't a strict science or rule, but a best practice depending on your repository, your scale, your organization, what your teams need, and more. This strategy has several advantages:
Some examples include:
@repo/ui: A package containing all of your shared UI components@repo/tool-specific-config: A package for managing configuration of a specific tool@repo/graphs: A domain-specific library for creating and manipulating graphical dataWhen you're creating Application Packages, it's best to avoid putting shared code in those packages. Instead, you should create a separate package for the shared code and have the application packages depend on that package.
Additionally, Application Packages are not meant to be installed into other packages. Instead, they should be thought of as an entrypoint to your Package Graph.
<Callout type="info"> There are [rare exceptions](/docs/core-concepts/package-types#installing-an-applicaiton-package-into-another-package) to this rule. </Callout>With a new Internal Package in place, you can start configuring tasks.