Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
bb646a6
feat: community add-ons
jycouet Mar 31, 2026
70cacaf
add changeset
jycouet Mar 31, 2026
60faa61
note for windows users
jycouet Mar 31, 2026
ec0bc1c
adding tests doc
jycouet Mar 31, 2026
ada56fe
fix to accommodate npm (not pnpm)
jycouet Mar 31, 2026
74230aa
Update documentation/docs/20-commands/20-sv-add.md
jycouet Mar 31, 2026
296d172
Update documentation/docs/30-add-ons/99-community.md
jycouet Mar 31, 2026
d48f88c
Update documentation/docs/30-add-ons/99-community.md
jycouet Mar 31, 2026
5ed99a2
Update documentation/docs/30-add-ons/99-community.md
jycouet Mar 31, 2026
d1d5a59
Update documentation/docs/30-add-ons/99-community.md
jycouet Mar 31, 2026
d21b1b7
Update documentation/docs/30-add-ons/99-community.md
jycouet Mar 31, 2026
6bc994b
Update documentation/docs/30-add-ons/99-community.md
jycouet Mar 31, 2026
fed0fca
Merge branch 'feat/community-add-ons' of github.com:sveltejs/cli into…
jycouet Mar 31, 2026
89bfbe3
update keyworkds
jycouet Mar 31, 2026
15dfa92
npmx
jycouet Apr 1, 2026
b903424
M
jycouet Apr 1, 2026
074589a
Update documentation/docs/20-commands/20-sv-add.md
jycouet Apr 1, 2026
304dc88
Update documentation/docs/20-commands/20-sv-add.md
jycouet Apr 1, 2026
c749319
Update documentation/docs/30-add-ons/99-community.md
jycouet Apr 1, 2026
9682efe
tweaks
jycouet Apr 1, 2026
6837ecc
Merge branch 'feat/community-add-ons' of github.com:sveltejs/cli into…
jycouet Apr 1, 2026
014e777
rmv no error
jycouet Apr 1, 2026
82647d7
fmt power²
jycouet Apr 1, 2026
8f180df
docs
jycouet Apr 1, 2026
5bcfcd3
docs pass
jycouet Apr 1, 2026
dcc8c37
update Project structure
jycouet Apr 1, 2026
6c5e1fe
improve issues msg
jycouet Apr 2, 2026
ce88d27
version info
jycouet Apr 2, 2026
f053ed5
add in --help
jycouet Apr 2, 2026
43d75fb
fmt²
jycouet Apr 2, 2026
c0500c0
v0 `sv` api docs
jycouet Apr 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/some-rings-appear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'sv': minor
'@sveltejs/sv-utils': minor
---

feat: community add-ons are now **experimental**
28 changes: 28 additions & 0 deletions documentation/docs/20-commands/20-sv-add.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,31 @@ Prevents installing dependencies
- [`tailwindcss`](tailwind)
- [`vitest`](vitest)

## Community add-ons

> [!NOTE]
> Community add-ons are currently **experimental**. The API may change. Don't use them in production yet!

> [!NOTE]
> Svelte maintainers have not reviewed community add-ons for malicious code!

Community add-ons are npm packages published by the community. Look out for add-ons from your favourite libraries and tools. _(soon)_ Many developers are building `sv` add-ons to make their integrations a one-liner. You can find them on [npmx](https://www.npmx.dev/search?q=keyword:sv-add) by searching for the keyword: `sv-add`.

```sh
# Install a community add-on by org name (it will look at @org/sv)
npx sv add @supacool

# Use a local add-on (for development or internal use)
npx sv add file:../path/to/my-addon

# Mix and match official and community add-ons
npx sv add eslint @supacool

# Also works when creating a new project directly
npx sv create --add eslint @supacool
```

> [!NOTE]
> On Windows PowerShell, `@` is a special character that should be escaped with single quotes. For example: `npx sv add '@supacool'`.

Want to create your own? Check the [Add-on Docs](community).
252 changes: 252 additions & 0 deletions documentation/docs/30-add-ons/99-community.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,257 @@
title: [create your own]
Copy link
Copy Markdown
Member

@teemingc teemingc Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love it

Image

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc @sacrosanctic 🧡

---

> [!NOTE]
> Community add-ons are currently **experimental**. The API may change. Don't use them in production yet!

This guide covers how to create, test, and publish community add-ons for `sv`.

## Quick start

The easiest way to create an add-on is by using the `addon` template:

```sh
npx sv create --template addon [path]
```

The newly created project will have a `README.md` and `CONTRIBUTING.md` to guide you along.

## Project structure

Typically, an add-on looks like this:

```js
import { transforms } from '@sveltejs/sv-utils';
import { defineAddon, defineAddonOptions } from 'sv';

export default defineAddon({
id: 'addon-name',

shortDescription: 'a better description of what your addon does ;)',

options: defineAddonOptions()
.add('who', {
question: 'To whom should the addon say hello?',
type: 'string' // boolean | number | select | multiselect
})
.build(),

setup: ({ dependsOn, isKit, unsupported }) => {
if (!isKit) unsupported('Requires SvelteKit');
dependsOn('vitest');
},

run: ({ isKit, cancel, sv, options, file, language, directory }) => {
// Add "Hello [who]!" to the root page
sv.file(
directory.kitRoutes + '/+page.svelte',
transforms.svelte(({ ast, svelte }) => {
svelte.addFragment(ast, `<p>Hello ${options.who}!</p>`);
})
);
},

nextSteps: ({ options }) => ['enjoy the add-on!']
});
```

The Svelte CLI is split into two packages with a clear boundary:

- [**`sv`**](sv) = **where and when** to do it. It owns paths, workspace detection, dependency tracking, and file I/O. The engine orchestrates add-on execution.
- [**`@sveltejs/sv-utils`**](sv-utils) = **what** to do to content. It provides parsers, language tooling, and typed transforms. Everything here is pure - no file system, no workspace awareness.

This separation means transforms are testable without a workspace and composable across add-ons.

## Development

You can run your add-on locally using the `file:` protocol:

```sh
cd /path/to/test-project
npx sv add file:../path/to/my-addon
```

This allows you to iterate quickly without publishing to npm.

The `file:` protocol also works for custom or private add-ons that you don't intend to publish - for example, to standardize project setup across your team or organization.

> [!NOTE]
> The `demo-add` script automatically builds your add-on before running it.

## Testing

The `sv/testing` module provides utilities for testing your add-on. `createSetupTest` is a factory that takes your vitest imports and returns a `setupTest` function. It creates real SvelteKit projects from templates, runs your add-on, and gives you access to the resulting files.

```js
import { expect } from '@playwright/test';
import fs from 'node:fs';
import path from 'node:path';
import { createSetupTest } from 'sv/testing';
import * as vitest from 'vitest';
import addon from './index.js';

const { test, testCases } = createSetupTest(vitest)(
{ addon },
{
kinds: [
{
type: 'default',
options: {
'your-addon-name': { who: 'World' }
}
}
],
filter: (testCase) => testCase.variant.includes('kit'),
browser: false
}
);

test.concurrent.for(testCases)('my-addon $kind.type $variant', async (testCase, ctx) => {
const cwd = ctx.cwd(testCase);

const page = fs.readFileSync(path.resolve(cwd, 'src/routes/+page.svelte'), 'utf8');
expect(page).toContain('Hello World!');
});
```

Your `vitest.config.js` must include the global setup from `sv/testing`:

```js
import { defineConfig } from 'vitest/config';

export default defineConfig({
test: {
include: ['tests/**/*.test.{js,ts}'],
globalSetup: ['tests/setup/global.js']
}
});
```

And the global test setup script `tests/setup/global.js`:

```js
import { fileURLToPath } from 'node:url';
import { setupGlobal } from 'sv/testing';

const TEST_DIR = fileURLToPath(new URL('../../.test-output/', import.meta.url));

export default setupGlobal({ TEST_DIR });
```

## Publishing

### Bundling

Community add-ons are bundled with [tsdown](https://tsdown.dev/) into a single file. Everything is bundled except `sv`. (It is a peer dependency provided at runtime.)

### `package.json`

Your add-on must have `sv` as a peer dependency and **no** `dependencies` in `package.json`:

```jsonc
{
"name": "@my-org/sv",
"version": "1.0.0",
"type": "module",
// bundled entrypoint (tsdown outputs .mjs for ESM)
"exports": {
".": { "default": "./dist/index.mjs" }
},
"publishConfig": {
"access": "public"
},
// cannot have dependencies
"dependencies": {},
"peerDependencies": {
// minimum version required to run by this add-on
"sv": "^0.13.0"
},
// Add the "sv-add" keyword so users can discover your add-on
"keywords": ["sv-add", "svelte", "sveltekit"]
}
```

### Naming convention

#### packages names

If you name your package `@my-org/sv`, users can install it by typing just the org handle:

```sh
npx sv add @my-org
```

It's also possible to publish like `@my-org/core`, just users will need to type the full package name.

```sh
npx sv add @my-org/core
```

Users can also ask for a specific version:

```sh
npx sv add @my-org/sv@1.2.3
```

When no version is specified, `latest` is used.

> [!NOTE]
> Unscoped packages are not supported yet

#### export options

`sv` first tries to import `your-package/sv`, then falls back to the default export. This means you have two options:

1. **Default export** (for dedicated add-on packages):

```json
{
"exports": {
".": "./src/index.js"
}
}
```

2. **`./sv` export** (for packages that also export other functionality):
```json
{
"exports": {
".": "./src/main.js",
"./sv": "./src/addon.js"
}
}
```

### Publish to npm

```sh
npm login
npm publish
```

> `prepublishOnly` automatically runs the build before publishing.

## Next steps

You can optionally display guidance in the console after your add-on runs:

```js
import { color } from '@sveltejs/sv-utils';

export default defineAddon({
// ...

nextSteps: ({ options }) => [
`Run ${color.command('npm run dev')} to start developing`,
`Check out the docs at https://...`
]
});
```

## Version compatibility

Your add-on should specify a minimum `sv` version in `peerDependencies`. Your users will get a compatibility warning if their `sv` version has a different major version than what was specified.

## Examples

See the [official add-on source code](https://github.com/sveltejs/cli/tree/main/packages/sv/src/addons) for some real world examples.
Loading
Loading