Skip to content

State of Svelte Wrap-up

In this State of Svelte event, our panelists discussed updates, LTS releases, and APIs, with Node.js maintainers, technical steering committee members, and collaborators.

In this wrap-up, we will take a deeper look into these latest developments, and explore what is on the horizon for Svelte. You can watch the full State of Svelte event on the This Dot Media YouTube Channel.

Here is a complete list of the host and panelists that participated in this online event.


  • Tracy Lee, CEO, This Dot Labs, @ladyleet
  • Rob Ocel, Team Lead & Software Architect, @robocell


  • Scott Spence, Svelte Society, Developer Relations Engineer at Storyblok, @spences10
  • Brittney Postma, Founder Svelte Sirens & Software Engineer Design Systems at Provi, @BrittneyPostma
  • Geoff Rich, Senior Software Engineer, Ordergroove | Svelte Core Team, @geoffrich_
  • Simon Holthausen, Software Engineer at Vercel | Full-time Svelte maintainer, @dummdidumm_
  • Kevin Åberg Kultalahti, Co-founder & Technical Community Builder at Svelte Society, Main Organizer at Svelte Summit, @kevmodrome

Svelte 4

The chat got off to a great start with a discussion about Svelte 4, and what we can expect with that release. Simon spoke about how it will be more of a maintenance update than anything else.

This version of Svelte will raise the minimum required Node version and use newer versions of Typescript as well. There will also be other minor breaking changes, but the release will mainly be focused on internally updating the repository by converting it to a mono-repo. As soon as these updates are done, Simon said they will immediately begin work on Svelte 5.

Typescript and Svelte

Scott brings up the reasons for not using Typescript in Svelte. Simon said a decision was made to transition the Svelte repository from using Typescript to using Javascript.

There were questions about why types and type safety were being taken away from the repository. Simon clarified that the repository will be getting rid of .TS files, but they are not getting rid of type checking with Typescript, and the code will still be fully typed checked at the same level as before. The plan is to do it through JS Docs.

JS Docs provides the same level of type safety you get through Typescript, but there is no longer a need for a compile step when using JS Docs. There is also no need to ship any Source Maps, and it should be easier to debug.

Kevin also wanted to be clear that Typescript can still be used when building a Svelte app.

Why Svelte?

Rob notes that the official release of Svelte happened about 4 months ago, and asks the panelists how the launch has been going so far.

Kevin goes first, talking about how everyone with whom he has talked about it has been very excited about it. He talks about how the form actions and data loading are very popular. In other frameworks, you have to attach event listeners, and then do the fetching on clients. Svelte simplifies all of that, and allows you to get rid of a lot of code by using the features in Svelte.

Svelte REPL

Kevin talks about the Svelte REPL, and how it plays into why Svelte is getting so big. Svelte isn’t just easy, it’s the fact that it is social in the fact that you can share a REPL and show someone how to do something with Svelte. If you have an issue, you can usually find a solution in the Svelte REPL.

Server and Client

Geoff talks about this aspect of Svelte. He says that they were treated as two separate entities, and there was talk about how to make them more interconnected so that it’s easier to use the server data, and get it into components.

In SvelteKit, you have a load function in a separate file that defines how that data is loaded. Svelte also calls a JSON endpoint and then that component in the JSON data.

State Management

Geoff brings up the simple state management model that Svelte has, and they really don’t want to give that up by implementing too many things like short syntax.

Simon adds that there is no real reason to bloat the syntax in the Svelte files. He doesn’t want the interoperability that Svelte currently offers.

Signals vs Store

A question is brought up about Signals vs Store, and if they are the same. Simon talks more about how they are related, but they are not necessarily the same. He explains that the API for Store is a little more settled right now where the API for Signals is a little more in exploration.

Usability is also different because Signals is more primitive, and everything is composed of functions which you call in a certain way. With Stores, you wrap a store and map the values that are pushed into something different.

How the panelists found out about Svelte

The latter part of this event focused on how each panelist found Svelte and got involved with it. It was a very interesting part of the conversation to hear the backgrounds of each panelist, and why they got more and more involved with Svelte and everything that was going with it. It went very in depth, and would be worth exploring more by watching the conversation unfold on the event video.


The panelists were very engaged, and there was a lot of dialogue about Svelte and the exciting things being done. The panelists also finished by bringing up ways to get involved with the Svelte community. You can watch the full State of Svelte event on the This Dot Media Youtube Channel.

This Dot Labs is a development consultancy that is trusted by top industry companies, including Stripe, Xero, Wikimedia, Docusign, and Twilio. This Dot takes a hands-on approach by providing tailored development strategies to help you approach your most pressing challenges with clarity and confidence. Whether it's bridging the gap between business and technology or modernizing legacy systems, you’ll find a breadth of experience and knowledge you need. Check out how This Dot Labs can empower your tech journey.

You might also like

Svelte 4: Unveiled Speed Enhancements and Developer-Centric Features cover image

Svelte 4: Unveiled Speed Enhancements and Developer-Centric Features

Svelte 4: Unveiled Speed Enhancements and Developer-Centric Features Svelte, a widely favored framework for building user interfaces, unveiled its much-anticipated version 4 on June 22. This major release, while paving the way for future advancements, brings a plethora of remarkable enhancements. Focusing on enriching the development experience and boosting performance, Svelte 4 is indeed reshaping the landscape of frontend development. In this post, we'll delve into the specifics of this exciting release, covering the significant performance boosts, enriched developer tools and features, revamped websites, and simplified migration guide. A Deeper Look at Performance Enhancements Svelte 4 delivers remarkable improvements in performance, focusing on shrinking the Svelte package size, and enhancing hydration efficiency. Streamlined Svelte Package Svelte 4 has substantially slimmed down, reducing its overall package size from 10.6 MB to a sleek 2.8 MB - a 75% decrease. This reduction in dependencies from 61 to 16 not only lightens Svelte but also optimizes SvelteKit, significantly accelerating the REPL experience and npm` install times. For instance, `npm install` times have been trimmed from over 5 minutes to less than a minute, a leap in quality that any developer will appreciate. NPM I Before: NPM I After: Bundle Size Before: Bundle Size After: Optimized Hydration and Performance Scores Alongside the impressive package size reduction, Svelte 4 offers more efficient code hydration, reducing the generated code size for the SvelteKit website by nearly 13%. This leaner codebase contributes to higher performance on benchmarks like Google Lighthouse. The performance score for the new Svelte 4 starter on has soared from 75% to a near perfect 95+%. Overall, the performance enhancements introduced with Svelte 4 mean a faster, more efficient, and smoother developer experience. Before: After: Enhanced Developer Experience in Svelte 4 Localized Transitions Transitions in Svelte 4 are local by default, preventing potential conflicts during page loading. `javascript // Transitions are now local in Svelte 4 let transition = local(/ ... */); ` Improved Web Component Authoring Web Components authoring is simplified with the dedicated customElement` attribute in `svelte:options`. `javascript ` Stricter Type Enforcement Svelte 4 introduces stricter types for createEventDispatcher`, `Action`, `ActionReturn`, and `onMount`. `javascript import { createEventDispatcher } from 'svelte'; const dispatch = createEventDispatcher(); // Svelte version 3: dispatch('optional'); dispatch('required'); // I can still omit the detail argument dispatch('noArgument', 'surprise'); // I can still add a detail argument // Svelte version 4 using TypeScript strict mode: dispatch('optional'); dispatch('required'); // error, missing argument dispatch('noArgument', 'surprise'); // error, cannot pass an argument ` These changes collectively offer a streamlined, robust, and efficient coding experience. Revamped Svelte Websites With Svelte 4, the team has also revamped its main website, offering an improved and more user-friendly experience. The Tutorial Website The Svelte tutorial website has been overhauled for an enhanced learning journey. New improvements include a visible file structure, fewer elements in the navbar, smoother navigation between sections, and a new dark mode. The Svelte Website The primary Svelte website received a makeover too, including better mobile navigation, improved TypeScript documentation, and a handy dark mode. These website updates aim to provide a more engaging, intuitive, and user-friendly experience for all Svelte users. A Smooth Migration to Svelte 4 Transitioning from Svelte 3 to Svelte 4 is designed to be as straightforward as possible. The Svelte team has provided an updated migration tool to simplify this process. Here is a step-by-step guide for the transition: 1. Run the Svelte migration tool. `shell npx svelte-migrate@latest svelte-4 ` 2. Remove Svelte 3 packages. `shell npm uninstall @babel/core babel-loader @sveltejs/package svelte-loader ` 3. Update your eslintrc.json` configuration file. `json { "root": true, "parser": "@typescript-eslint/parser", "extends": [ "eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:svelte/recommended", "prettier", "plugin:storybook/recommended" ], "plugins": ["@typescript-eslint", "prettier"], "ignorePatterns": [".cjs"], "overrides": [ { "files": [".svelte"], "parser": "svelte-eslint-parser", "parserOptions": { "parser": "@typescript-eslint/parser" } } ], "parserOptions": { "sourceType": "module", "ecmaVersion": 2020 }, "env": { "browser": true, "es2017": true, "node": true }, "globals": { "NodeJS": true, "svelte": true } } ` 4. Upgrade Storybook related packages to the latest v7. Note: as of the publishing of this article, the latest version is 7.0.26. `shell npx storybook@latest upgrade ` Do note that the minimum version requirements have changed. You will now need: - NodeJS 16 or higher - SvelteKit 1.20.4 or higher - TypeScript 5 or higher For more detailed instructions and information, please refer to the official Svelte 4 migration guide or you can take a look at our Svelte 4 starter kit on The focus is to ensure a hassle-free transition, allowing developers to take advantage of the new features and enhancements Svelte 4 offers without significant obstacles. Conclusion Svelte 4, with its performance enhancements and streamlined development process, offers a new pinnacle in the realm of JavaScript frameworks. If you're keen on shifting from Svelte 3 to Svelte 4, a comprehensive migration guide is provided to facilitate a smooth transition. For a quick start with Svelte 4, check out our ready-to-use Svelte Kit with SCSS Starter Kit. In addition, we've developed two showcases demonstrating Svelte 4's power: 1. Svelte Kit with SCSS & 7GUIs - A comprehensive demo showcasing various UI challenges. 2. GitHub Replica Showcase - A clone of the popular code hosting platform, GitHub, demonstrating the potential of Svelte 4 in building complex and high-performance web applications. In conclusion, Svelte 4 brings numerous performance improvements and enriches the development experience, thereby increasing developer productivity and enabling the creation of more efficient applications. Its thoughtful design, alongside the streamlined migration process, is set to expand its adoption in the web development community....

A Deep Dive into SvelteKit Routing with Our GitHub Showcase Example cover image

A Deep Dive into SvelteKit Routing with Our GitHub Showcase Example

Introduction SvelteKit is an excellent framework for building web applications of all sizes, with a beautiful development experience and flexible filesystem-based routing. At the heart of SvelteKit is a filesystem-based router. The routes of your app — i.e. the URL paths that users can access — are defined by the directories in your codebase. In this tutorial, we are going to discuss SvelteKit routing with an awesome SvelteKit GitHub showcase built by This Dot Labs. The showcase is built with the SvelteKit starter kit on We are going to tackle: - Filesystem-based router - +page.svelte - +page.server - +layout.svelte - +layout.server - +error.svelte - Advanced Routing - Rest Parameters - (group) layouts - Matching Below is the current routes folder. Prerequisites You will need a development environment running Node.js; this tutorial was tested on Node.js version 16.18.0, and npm version 8.19.2. Filesystem-based router The src/routes` is the root route. You can change `src/routes` to a different directory by editing the project config. `js // svelte.config.js / @type {import('@sveltejs/kit').Config} */ const config = { kit: { routes: "src/routes", // 👈 you can change it here to anything you want }, }; ` Each route directory contains one or more route files, which can be identified by their + prefix. +page.svelte A +page.svelte` component defines a page of your app. By default, pages are rendered both on the server (SSR) for the initial request, and in the browser (CSR) for subsequent navigation. In the below example, we see how to render a simple login page component: ` // src/routes/signin/(auth)/+page.svelte import Auth from '$lib/components/auth/Auth.svelte'; ` +page.ts Often, a page will need to load some data before it can be rendered. For this, we add a +page.js` (or `+page.ts`, if you're TypeScript-inclined) module that exports a load function. +page.server.ts` If your load function can only run on the server— ie, if it needs to fetch data from a database or you need to access private environment variables like API key— then you can rename +page.js` to `+page.server.js`, and change the `PageLoad` type to `PageServerLoad`. To pass top user repository data, and user’s gists to the client-rendered page, we do the following: `ts // src/routes/(authenticated)/(home)/+page.server.ts import type { PageServerLoad } from "./$types"; import { mapUserReposToTopRepos, mapGistsToHomeGists } from "$lib/helpers"; import type { UserGistsApiResponse, UserReposApiResponse, } from "$lib/interfaces"; import { ENV } from "$lib/constants/env"; export const load: PageServerLoad = async ({ fetch, parent }) => { const repoURL = new URL("/user/repos", ENV.GITHUBURL); repoURL.searchParams.append("sort", "updated"); repoURL.searchParams.append("perpage", "20"); const { userInfo } = await parent(); const gistsURL = new URL( /users/${userInfo?.username}/gists`, ENV.GITHUBURL ); try { const reposPromise = await fetch(repoURL); const gistsPromise = await fetch(gistsURL); const [repoRes, gistsRes] = await Promise.all([reposPromise, gistsPromise]); const gists = (await gistsRes.json()) as UserGistsApiResponse; const repos = (await repoRes.json()) as UserReposApiResponse; return { topRepos: mapUserReposToTopRepos(repos), gists: mapGistsToHomeGists(gists), username: userInfo?.username, }; } catch (err) { console.log(err); } }; ` The page.svelte` gets access to the data by using the data variable which is of type `PageServerData`. `html import TopRepositories from '$lib/components/TopRepositories/TopRepositories.svelte'; import Gists from '$lib/components/Gists/Gists.svelte'; import type { PageServerData } from './$types'; export let data: PageServerData; {#if data?.gists} {/if} {#if data?.topRepos} {/if} @use 'src/lib/styles/variables.scss'; .page-container { display: grid; grid-template-columns: 1fr; background: variables.$gray100; @media (min-width: variables.$md) { grid-template-columns: 24rem 1fr; } } aside { background: variables.$white; padding: 2rem; @media (max-width: variables.$md) { order: 2; } } ` +layout.svelte As there are elements that should be visible on every page, such as top-level navigation or a footer. Instead of repeating them in every +page.svelte, we can put them in layouts. The only requirement is that the component includes a ` for the page content. For example, let's add a nav bar: `html import NavBar from '$lib/components/NavBar/NavBar.svelte'; import type { LayoutServerData } from './$types'; export let data: LayoutServerData; // 👈 child routes of the layout page ` +layout.server.ts Just like +page.server.ts`, your `+layout.svelte` component can get data from a load function in `+layout.server.js`, and change the type from `PageServerLoad` type to LayoutServerLoad. `ts // src/routes/(authenticated)/+layout.server.ts import { ENV } from "$lib/constants/env"; import { remapContextUserAsync } from "$lib/helpers/context-user"; import type { LayoutServerLoad } from "./$types"; import { mapUserInfoResponseToUserInfo } from "$lib/helpers/user"; export const load: LayoutServerLoad = async ({ locals, fetch }) => { const getContextUserUrl = new URL("/user", ENV.GITHUBURL); const response = await fetch(getContextUserUrl.toString()); const contextUser = await remapContextUserAsync(response); locals.user = contextUser; return { userInfo: mapUserInfoResponseToUserInfo(locals.user), }; }; ` +error.svelte If an error occurs during load, SvelteKit will render a default error page. You can customize this error page on a per-route basis by adding an +error.svelte file. In the showcase, an error.svelte` page has been added for authenticated view in case of an error. `html import { page } from '$app/stores'; import ErrorMain from '$lib/components/ErrorPage/ErrorMain.svelte'; import ErrorFlash from '$lib/components/ErrorPage/ErrorFlash.svelte'; ` Advanced Routing Rest Parameters If the number of route segments is unknown, you can use spread operator syntax. This is done to implement Github’s file viewer. ` /[org]/[repo]/tree/[branch]/[...file] `` would result in the following parameters being available to the page: `js { org: ‘thisdot’, repo: '', branch: 'main', file: ‘/starters/svelte-kit-scss/' } ` (group) layouts By default, the layout hierarchy mirrors the route hierarchy. In some cases, that might not be what you want. In the GitHub showcase, we would like an authenticated user to be able to have access to the navigation bar, error page, and user information. This is done by grouping all the relevant pages which an authenticated user can access. Grouping can also be used to tidy your file tree and ‘group’ similar pages together for easy navigation, and understanding of the project. Matching In the Github showcase, we needed to have a page to show issues and pull requests for a single repo. The route src/routes/(authenticated)/[username]/[repo]/[issues]` would match `/thisdot/` or `/thisdot/` but also `/thisdot/` and we don't want that. You can ensure that route parameters are well-formed by adding a matcher— which takes only `issues` or `pull-requests`, and returns true if it is valid– to your params directory. `ts // src/params/issuesearch_type.ts import { IssueSearchPageTypeFiltersMap } from "$lib/constants/matchers"; import type { ParamMatcher } from "@sveltejs/kit"; export const match: ParamMatcher = (param: string): boolean => { return Object.keys(IssueSearchPageTypeFiltersMap).includes( param?.toLowerCase() ); }; ` `ts // src/lib/constants/matchers.ts import { IssueSearchQueryType } from './issues-search-query-filters'; export const IssueSearchPageTypeFiltersMap = { issues: ‘issues’, pulls: ’pull-requests’, }; export type IssueSearchTypePage = keyof typeof IssueSearchPageTypeFiltersMap; ` ...and augmenting your routes: ` [issueSearchType=issuesearch_type] ` If the pathname doesn't match, SvelteKit will try to match other routes (using the sort order specified below), before eventually returning a 404. Note: Matchers run both on the server and in the browser.` Conclusion In this article, we learned about basic and advanced routing in SvelteKit by using the SvelteKit showcase example. We looked at how to work with SvelteKit's Filesystem-based router, rest parameters, and (group) layouts. If you want to learn more about SvelteKit, please check out the SvelteKit and SCSS starter kit and the SvelteKit and SCSS GitHub showcase. All the code for our showcase project is open source. If you want to collaborate with us or have suggestions, we're always welcome to new contributions. Thanks for reading! If you have any questions, or run into any trouble, feel free to reach out on Twitter....

State of RxJS Wrap-up cover image

State of RxJS Wrap-up

In this State of RxJS event, our panelists discussed the current state of RxJS and the upcoming features and improvements of the highly anticipated RxJS 8 release. In this wrap-up, we will talk about panel discussions with RxJS core team members, which is an in-depth exploration of the upcoming RxJS 8 release, highlighting its key features and performance enhancements. You can watch the full State of RxJS event on the This Dot Media YouTube Channel. Here is a complete list of the host and panelists that participated in this online event. Hosts: - Tracy Lee, CEO, This Dot Labs, @ladyleet - Ben Lesh, RxJs Core Team Lead, @BenLesh Panelists: - Mladen Jakovljević, Frontend Web Developer, RxJS Core Team member, @jakovljeviMla - Moshe Kolodny, Senior Full Stack Engineer at Netflix, Previous RxJS Lead at Google, @mkldny - Marko Stanimirović, NgRx Core Team Member | GDE in Angular, @MarkoStDev State of RxJS__ Ben kicks off the discussion by updating everyone on the current state of RxJS. He starts off by recommending those using RxJS v6 to update to the current version 7.4 because it is about half the size of v6, and he says that v8 will reduce the size even further. There are also performance updates with 7.4 where the speeds improved 30 fold. RxJS version 8 is currently in alpha! There are not as many breaking changes with this version. The major breaking change in this version is that they are removing the long deprecated APIs. They are really wanting people to try things in the alpha version, especially the 408 loops to subscribe to observables. It is an interesting way to consume observables that use the platform, and may work really well with other people’s async await usage. Operators__ The team is currently trying to figure out a way to show people how they develop operators by giving them the means of developing operators. They currently have a problem where they externally tell people to develop an operator with this, you subscribe, and then you give this kind of hand rolled Observer there. Internally, they have a createOperatorSubscriber which replaces the operate function. They want a reference where you can see how to develop an operator using the ones already there to build your own. There is also a plan to make sure that the RxJS library works as a utility library to work with any Observable that matches the contract. Docs__ Mladen gives an update of the docs for RxJS. He explains that there aren’t a lot of updates currently with the docs. He explains that there were some issues in the past with exporting operators from two places. There was also an issue with the Docs app build running in the pipeline. He explains that these issues should now be resolved, and that there hopefully won’t be any more issues there. Pull requests are always welcome when working with RxJS docs. They try to stay on top of merge requests as well. NgRx__ Marko talks about NgRx and RxJS. He explains that RxJS is the main engine of NgRx for almost all of the libraries, especially State Management. A few packages, like direct store, implements a Redux pattern, but uses RxJS under the hood. Pipe__ Moshe brings up the typings for pipe. All of RxJS’s pipe methods and functions, including the new RxJS function, will work with any unary function. General Questions__ One of the first questions brought up was if RxJS should not be associated with Angular anymore. Ben brings up the fact that recently, there have been a lot of React people downloading RxJS. Another question was why NgRx is switching to Signals. Marco talks about how NgRx is a group of libraries that is used in Angular. NgRx needs to be in accordance with Angular. One main reason is because of the performance improvements with the change detection strategy. There were also other questions about contributing to RxJS and coming up with a way to utilize the docs for that. There are also questions about the RxJS community, and that there currently isn’t a discord or anything like that for it right now. Conclusion__ The panelists were very engaged, and there was a lot of dialogue about RxJS and the future that is to come with it. The question and answer portion at the end covered some great material that all the panelists took part in answering. You can watch the full State of RxJS event on the This Dot Media Youtube Channel....

Testing a Fastify app with the NodeJS test runner cover image

Testing a Fastify app with the NodeJS test runner

Introduction Node.js has shipped a built-in test runner for a couple of major versions. Since its release I haven’t heard much about it so I decided to try it out on a simple Fastify API server application that I was working on. It turns out, it’s pretty good! It’s also really nice to start testing a node application without dealing with the hassle of installing some additional dependencies and managing more configurations. Since it’s got my stamp of approval, why not write a post about it? In this post, we will hit the highlights of the testing API and write some basic but real-life tests for an API server. This server will be built with Fastify, a plugin-centric API framework. They have some good documentation on testing that should make this pretty easy. We’ll also add a SQL driver for the plugin we will test. Setup Let's set up our simple API server by creating a new project, adding our dependencies, and creating some files. Ensure you’re running node v20 or greater (Test runner is a stable API as of the 20 major releases) Overview `index.js` - node entry that initializes our Fastify app and listens for incoming http requests on port 3001 `app.js` - this file exports a function that creates and returns our Fastify application instance `sql-plugin.js` - a Fastify plugin that sets up and connects to a SQL driver and makes it available on our app instance Application Code A simple first test For our first test we will just test our servers index route. If you recall from the app.js` code above, our index route returns a 501 response for “not implemented”. In this test, we're using the createApp` function to create a new instance of our Fastify app, and then using the `inject` method from the Fastify API to make a request to the `/` route. We import our test utilities directly from the node. Notice we can pass async functions to our test to use async/await. Node’s assert API has been around for a long time, this is what we are using to make our test assertions. To run this test, we can use the following command: By default the Node.js test runner uses the TAP reporter. You can configure it using other reporters or even create your own custom reporters for it to use. Testing our SQL plugin Next, let's take a look at how to test our Fastify Postgres plugin. This one is a bit more involved and gives us an opportunity to use more of the test runner features. In this example, we are using a feature called Subtests. This simply means when nested tests inside of a top-level test. In our top-level test call, we get a test parameter t` that we call methods on in our nested test structure. In this example, we use `t.beforeEach` to create a new Fastify app instance for each test, and call the `test` method to register our nested tests. Along with `beforeEach` the other methods you might expect are also available: `afterEach`, `before`, `after`. Since we don’t want to connect to our Postgres database in our tests, we are using the available Mocking API to mock out the client. This was the API that I was most excited to see included in the Node Test Runner. After the basics, you almost always need to mock some functions, methods, or libraries in your tests. After trying this feature, it works easily and as expected, I was confident that I could get pretty far testing with the new Node.js core API’s. Since my plugin only uses the end method of the Postgres driver, it’s the only method I provide a mock function for. Our second test confirms that it gets called when our Fastify server is shutting down. Additional features A lot of other features that are common in other popular testing frameworks are also available. Test styles and methods Along with our basic test` based tests we used for our Fastify plugins - `test` also includes `skip`, `todo`, and `only` methods. They are for what you would expect based on the names, skipping or only running certain tests, and work-in-progress tests. If you prefer, you also have the option of using the describe` → `it` test syntax. They both come with the same methods as `test` and I think it really comes down to a matter of personal preference. Test coverage This might be the deal breaker for some since this feature is still experimental. As popular as test coverage reporting is, I expect this API to be finalized and become stable in an upcoming version. Since this isn’t something that’s being shipped for the end user though, I say go for it. What’s the worst that could happen really? Other CLI flags —watch` - —test-name-pattern` - TypeScript support You can use a loader like you would for a regular node application to execute TypeScript files. Some popular examples are tsx` and `ts-node`. In practice, I found that this currently doesn’t work well since the test runner only looks for JS file types. After digging in I found that they added support to locate your test files via a glob string but it won’t be available until the next major version release. Conclusion The built-in test runner is a lot more comprehensive than I expected it to be. I was able to easily write some real-world tests for my application. If you don’t mind some of the features like coverage reporting being experimental, you can get pretty far without installing any additional dependencies. The biggest deal breaker on many projects at this point, in my opinion, is the lack of straightforward TypeScript support. This is the test command that I ended up with in my application: I’ll be honest, I stole this from a GitHub issue thread and I don’t know exactly how it works (but it does). If TypeScript is a requirement, maybe stick with Jest or Vitest for now 🙂...