Skip to content

1: Creating the app

1.1: Install Meteor

First, we need to install Meteor by following this installation guide.

1.2: Create Meteor Project

The easiest way to setup Meteor with Svelte is by using the command meteor create with the option --svelte and your project name:

shell
meteor create --svelte simple-todos-svelte

Meteor will create all the necessary files for you. With --svelte option, Meteor generates a project using Svelte 5 and Rspack as the bundler, and this is the approach walked through in this tutorial. Using the Rspack bundler is the default convention in Meteor 3.4+, as it improves dev speed, enables more build features, and provides better control over bundle size and configuration.

We provide the final app for both the Rspack and Meteor bundlers. This guide follows the Rspack version and reaches the same final state. The Meteor bundler version is for those who prefer the legacy bundler.

INFO

You can find the final version of this app on GitHub using the Rspack bundler or the Meteor bundler.

The files located in the client directory are setting up your client side (web), you can see for example client/main.html where Meteor is rendering your App main component into the HTML.

Also, check the server directory where Meteor is setting up the server side (Node.js), you can see the server/main.js which would be a good place to initialize your MongoDB database with some data. You don't need to install MongoDB as Meteor provides an embedded version of it ready for you to use.

You can now run your Meteor app using:

shell
meteor

Don't worry, Meteor will keep your app in sync with all your changes from now on.

Take a quick look at all the files created by Meteor, you don't need to understand them now but it's good to know where they are.

Your Svelte code will be located inside the imports/ui directory, and the App.svelte file will be the root component of your Svelte To-do app.

1.3: Create Tasks

To start working on our todo list app, let’s replace the code of the default starter app with the code below. From there, we’ll talk about what it does.

First, let’s simplify our HTML entry point like so:

html
<head>
  <title>Simple todo</title>
</head>

<body>
  <div id="app"></div>
</body>

The client/main.js file should import and render the main Svelte component:

js
import { Meteor } from 'meteor/meteor';
import App from '../imports/ui/App.svelte';
import { mount, unmount } from 'svelte';

let app; // will hold the mounted instance

Meteor.startup(() => {
  const target = document.getElementById('app');

  // (Re)mount
  app = mount(App, { target });

  // Clean up on HMR so we don't double-mount
  if (import.meta.webpackHot) {
    import.meta.webpackHot.accept();
    import.meta.webpackHot.dispose(() => {
      if (app) {
        // pass the instance you got from mount()
        unmount(app, { outro: false }); // set outro:true if you want transitions
        app = null;
      }
      // optional: clear target to be extra safe
      target.innerHTML = '';
    });
  }
});

Inside the imports/ui folder let us modify App.svelte to display a header and a list of tasks:

html
<script>
  import { Meteor } from "meteor/meteor";

  let tasks = [
    { text: 'This is task 1' },
    { text: 'This is task 2' },
    { text: 'This is task 3' },
  ];
</script>

<div class="container">
  <header>
    <h1>Todo List</h1>
  </header>

  <ul>
    {#each tasks as task (task.text)}
      <li>{task.text}</li>
    {/each}
  </ul>
</div>

We just modified our main Svelte component App.svelte, which will be rendered into the #app div in the body. It shows a header and a list of tasks. For now, we're using static sample data to display the tasks.

1.4: View Sample Tasks

As you are not connecting to your server and database yet, we’ve defined some sample data directly in App.svelte to render a list of tasks.

At this point meteor should be running on port 3000 so you can visit the running app and see your list with three tasks displayed at http://localhost:3000/ - but if meteor is not running, go to your terminal and move to the top directory of your project and type meteor then press return to launch the app.

All right! Let’s find out what all these bits of code are doing!

1.5: Rendering Data

In Svelte with Meteor, your main entry point is client/main.js, which imports and mounts your root Svelte component App.svelte to a target element in the HTML like <div id="app"></div>

Svelte components are defined in .svelte files, which can include <script>, <style>, and HTML markup. The HTML markup can use Svelte's templating syntax, such as {#each} for looping and {expression} for interpolating data.

You can define reactive data and logic in the <script> tag. In the code above, we defined a tasks array directly in the component. Inside the markup, we use {#each tasks as task} to iterate over the array and display each task's text property using {task.text}

For Meteor-specific reactivity (like subscriptions and collections), Svelte in Meteor uses Tracker and reactive variables to integrate with Meteor's reactivity system. We'll cover that in later steps.

1.6: Mobile Look

Let’s see how your app is looking on mobile. You can simulate a mobile environment by right clicking your app in the browser (we are assuming you are using Google Chrome, as it is the most popular browser) and then inspect, this will open a new window inside your browser called Dev Tools. In the Dev Tools you have a small icon showing a Mobile device and a Tablet:

Click on it and then select the phone that you want to simulate and in the top nav bar.

You can also check your app in your personal cellphone. To do so, connect to your App using your local IP in the navigation browser of your mobile browser.

This command should print your local IP for you on Unix systems ifconfig | grep "inet " | grep -Fv 127.0.0.1 | awk '{print $2}'

On Microsoft Windows try this in a command prompt ipconfig | findstr "IPv4 Address"

You should see the following:

As you can see, everything is small, as we are not adjusting the view port for mobile devices. You can fix this and other similar issues by adding these lines to your client/main.html file, inside the head tag, after the title.

html
...
  <meta charset="utf-8"/>
  <meta http-equiv="x-ua-compatible" content="ie=edge"/>
  <meta
      name="viewport"
      content="width=device-width, height=device-height, viewport-fit=cover, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
  />
  <meta name="mobile-web-app-capable" content="yes"/>
  <meta name="apple-mobile-web-app-capable" content="yes"/>
...

Now your app should scale properly on mobile devices and look like this:

1.7: Hot Module Replacement

Starting from Meteor 3.4+, new apps use Rspack by default. It includes built-in Hot Module Replacement (HMR) and solid-refresh. This lets you see changes as you make them, even inside Solid components, without losing component state.

If you use a previous Meteor version, you can opt in to the hot-module-replacement which is already added for you. This package updates the javascript modules in a running app that were modified during a rebuild. Reduces the feedback cycle while developing, so you can view and test changes quicker (it even updates the app before the build has finished). You are also not going to lose the state, your app code will be updated, and your state will be the same.

WARNING

hot-module-replacement can still be added to a Meteor app when using Meteor-Rspack with the rspack Atmosphere package enabled (3.4+). It acts as the HMR strategy for modules that are still compiled by the Meteor bundler, such as Atmosphere packages or any files explicitly kept on the Meteor bundler side.

In previous Meteor versions, reactivity with Svelte was often handled by packages like zodern:melte, which provided sugar syntax like $m: for reactive statements. However, with Meteor 3.4+ using the Rspack bundler, we now use a more standard approach that's compatible with the latest Svelte versions.

You can read more about packages here.

WARNING

zodern:melte package is not compatible with Meteor Rspack apps (Meteor 3.4+ using the rspack package). This transition away from zodern:melte brings significant advantages, including support for the latest versions of Svelte 5 and better compatibility with the broader Svelte ecosystem. While we lose some sugar syntax helpers, we gain a more standard and future-proof implementation that will evolve alongside Svelte itself.

You can also opt in to add the package dev-error-overlay when using previous versions, so you can see the errors in your web browser.

shell
meteor add dev-error-overlay

You can try to make some mistakes and then you are going to see the errors in the browser and not only in the console.

In the next step we are going to work with our MongoDB database to be able to store our tasks.