Skip to content

Getting Started with Vuetify in Vue 3

This article was written over 18 months ago and may contain information that is out of date. Some content may be relevant but please refer to the relevant official documentation or available resources for the latest information.

If you're here to learn about Vuetify and how to use it with Vue 3, you've come to the right place. In this article, we'll introduce Vuetify, a Material Design component framework for Vue.js, and walk you through setting it up in a Vue 3 project.

We will also build a simple web app that allows us to create and vue jokes. Oh, sorry, view* jokes!

What is Vuetify?

Vuetify is a VueJS Material Design component framework. That is to say that Vuetify provides us with prebuilt components and features (e.g. internationalization, tree shaking, theming, etc.) to help us build Vue applications faster. Additionally, Vuetify components have built-in standard functionality, such as validation in form inputs, or various disabled states in buttons.

You can check out a full list of components supported by Vuetify on their official documentation website.

Setting things up

Before we get started, you will need the following on your machine:

  • NodeJS installed
  • A NodeJS package manager e.g. yarn or npm installed
  • Intermediate knowledge of Vue 3.x with the composition API

If you’d like to follow along, feel free to clone the github repository for this article.

git clone https://github.com/thisdot/blog-demos.git
# or `git@github.com:thisdot/blog-demos.git` for ssh

# then cd into the project directory
cd getting-started-with-vuetify

Installing Vuetify

We will be using yarn to install and setup Vuetify 3 (the version that supports Vue 3) in this case.

First, let's create a new Vuetify project. You can do this by running the following command in your terminal or command prompt:

yarn create vuetify

This will create a new Vuetify project. For our jokes app, we will use the Essentials (Vuetify, VueRouter, Pinia) preset when creating our app. We will also be using TypeScript for our app, but this is not necessary.

Since VueJS allows us to build incrementally, if you would like to instead add Vuetify to an existing project, you can use the manual steps provided by the Vuetify team.

Testing our application

Once we have installed and configured our application, cd into the project's directly, and run the app using the following command:

yarn dev #or `npm run dev` (if using npm instead)

Visit localhost:3000/ to see your app in action.

Vuetify project folder structure

Our Vuetify project is generally structured as follows:

  • public - Contains static assets that do not need preprocessing eg. our application favicon
  • src - Contains our VueJS source code. We'll mostly be working here.
    • assets - Assets that need to be preprocessed eg. our images that may need to be compressed when building for production
    • components
    • layouts - Layouts
    • plugins - Everything gets wired up here (registration of our app as well as vuetify, our router & pinia)
    • router - Vue router-related functionality
    • store - Pinia store
    • styles
    • views - our web app's "pages"

Worth noting before building

It is worth noting that all components in Vuetify start with a v- for example:

  • v-form is a form
  • v-btn is a button component
  • v-text-field is an input field

and so on and so forth.

When creating your own components, it is recommended to use a different naming approach so that it is easier to know which components are Vuetify components, and which ones are your components.

Building our Vuetify application

We will build a web app that allows us to add, view and delete jokes.

image

Here are the steps we will take to build our app:

  • Delete unnecessary boilerplate from generated Vuetify app
  • Add a joke pinia store - we'll be using this to store our jokes globally using Pinia
  • Create our joke components
    • components/jokes/CreateJokeForm.vue - the form that allows us to add jokes
    • components/jokes/JokeList.vue - Lists our jokes out.
  • Add our components to our Home.vue to view them in our home page

Setting up the jokes pinia store

In the src/store/ directory, create a new file called joke.ts that will serve as our Pinia store for storing our jokes. The file content for this will be as follows:

import { defineStore } from "pinia";

export interface Joke {
  id: number;
  title: string;
  punchline: string;
}

export const useJokeStore = defineStore({
  id: "joke",
  state: () => ({
    jokes: [] as Joke[],
  }),
  actions: {
    addJoke(joke: Joke) {
      this.jokes.push(joke);
    },
    removeJoke(id: number) {
      this.jokes = this.jokes.filter((joke) => joke.id !== id);
    },
  },
});

This code defines a special storage space called a "store" for jokes in our Vue.js app. This store keeps track of all the jokes we've added through our app's form. Each joke has an ID, title, and punchline.

The addJoke function in the store is used to add a new joke to the store when a user submits the form. The removeJoke function is used to delete a joke from the store when a user clicks the delete button.

By using this store, we can keep track of all the jokes that have been added through the app, and we can easily add or remove jokes without having to manage the list ourselves.

Creating the joke components

CreateJokeForm.vue

Create a file in src/components/jokes/ called CreateJokeForm.vue. This file defines a Vue.js component that displays a form for adding new jokes. The file should have the following contents:

Template section

<template>
  <v-form @submit.prevent="submitJoke">
    <v-text-field
      v-model="jokeTitle"
      label="Joke Title"
      outlined
      required
    ></v-text-field>
    <v-text-field
      v-model="jokePunchline"
      label="Joke Punchline"
      outlined
      required
    ></v-text-field>

    <v-btn
      color="primary"
      :disabled="!jokeTitle || !jokePunchline"
      type="submit"
      >Submit Joke</v-btn
    >
  </v-form>
</template>

In the template section, we define a form using the v-form component from Vuetify. We bind the form's submit event to the submitJoke method, which will be called when the form is submitted.

Inside the form, we have two text fields" one for the joke title, and one for the punchline. These text fields are implemented using the v-text-field component from Vuetify. The label prop sets the label for each text field, and the outlined prop creates an outlined style for each text field. The required prop sets the fields as required, meaning that they must be filled in before the form can be submitted.

Finally, we have a submit button implemented using the v-btn component from Vuetify. The button is disabled until both the title and punchline fields are filled in, which is accomplished using the :disabled prop with a computed property that checks if both fields are empty.

Script section

<script lang="ts" setup>
import { computed, ref } from "vue";
import { Joke, useJokeStore } from "@/store/joke";

const jokeStore = useJokeStore();

const jokeTitle = ref("");
const jokePunchline = ref("");

const joke = computed<Joke>(() => ({
  id: jokeStore.jokes.length + 1,
  title: jokeTitle.value,
  punchline: jokePunchline.value,
}));

function submitJoke() {
  jokeStore.addJoke(joke.value);
  jokeTitle.value = "";
  jokePunchline.value = "";
}
</script>

In the script section, we import some functions and types from Vue.js and the joke store. We then define a jokeStore variable that holds the instance of the useJokeStore function from the joke store.

We also define two refs, jokeTitle, and jokePunchline, which hold the values of the form's title and punchline fields, respectively.

We then define a computed property, joke, which creates a new Joke object using the jokeTitle and jokePunchline refs, as well as the length of the jokes array in the jokeStore to set the id property.

Finally, we define a submitJoke function that calls the addJoke method from the jokeStore to add the new joke object to the store. We also reset the jokeTitle and jokePunchline refs to empty strings.

JokeList.vue

Template section

This one looks bulky. But in essence, all we are doing is displaying a list of jokes when they are found, and a message that lets us know that there are no jokes if we have none that have been added.

<template>
  <v-card>
    <v-card-title>
      My Jokes
      <v-icon icon="mdi-emoticon-excited-outline"></v-icon>
    </v-card-title>
    <v-card-text>
      <v-list v-if="jokeStore.jokes.length">
        <v-list-item v-for="joke in jokeStore.jokes" :key="joke.id">
          <v-row>
            <v-col cols="10">
              <v-list-item-subtitle>{{ joke.title }}</v-list-item-subtitle>
              <v-list-item-title>
                {{ joke.punchline }}
              </v-list-item-title>
            </v-col>
            <v-col cols="2">
              <v-list-item-action>
                <v-btn
                  color="error"
                  variant="outlined"
                  @click="deleteJoke(joke)"
                >
                  <v-icon>mdi-delete</v-icon>
                </v-btn>
              </v-list-item-action>
            </v-col>
          </v-row>
        </v-list-item>
      </v-list>
      <v-alert v-else type="info"> You have no jokes. Add some! </v-alert>
    </v-card-text>
  </v-card>
</template>

In the template section, we define a v-card component, which is a container component used to group related content in Vuetify. The card contains a title, which includes an excited emoticon icon from the mdi-emoticon-excited-outline icon set from Material Design Icons, displayed using the v-icon component.

The jokes are displayed in a v-list, which is a component used to display lists in Vuetify. Each joke is represented by a v-list-item containing a title and subtitle. The v-row and v-col components from Vuetify are used to divide each list item into two columns: one column for the joke title and punchline, and another column for the delete button.

The delete button is implemented using the v-btn component from Vuetify. The button is red, and outlined using the color="error" and variant="outlined" props, respectively. The @click event is used to call the deleteJoke function when the button is clicked.

If there are no jokes in the jokeStore, the component displays an v-alert component with a message to add some jokes.

Script section

<script setup lang="ts">
import { Joke, useJokeStore } from "@/store/joke";

const jokeStore = useJokeStore();

function deleteJoke(joke: Joke) {
  jokeStore.removeJoke(joke.id);
}
</script>

In the script section, we import some functions and types from the joke store. We then define a jokeStore variable that holds the instance of the useJokeStore function from the joke store.

We also define a deleteJoke function that takes a joke object as an argument and calls the removeJoke method from the jokeStore to remove the joke from the store.

This component is called JokeList.vue and displays a list of jokes using Vuetify components like v-card, v-list, v-list-item, v-row, v-col, and v-btn. The component includes a deleteJoke function to remove a joke from the jokeStore as well.

Wiring it up

To display our form as well as list of jokes, we will go to the src/views/Home.vue file and change its contents to the following:

<template>
  <v-container>
    <v-row>
      <v-col cols="12" md="6">
        <CreateJokeForm />
      </v-col>
      <v-col cols="12" md="6">
        <JokeList />
      </v-col>
    </v-row>
  </v-container>
</template>

<script lang="ts" setup>
import CreateJokeForm from "@/components/jokes/CreateJokeForm.vue";
import JokeList from "@/components/jokes/JokeList.vue";
</script>

The Home.vue file defines a Vue.js view that displays the home page of our app. The view contains a v-container component, which is a layout component used to provide a responsive grid system for our app.

Inside the v-container, we have a v-row component, which is used to create a horizontal row of content. The v-row contains two v-col components, each representing a column of content. The cols prop specifies that each column should take up 12 columns on small screens (i.e. the entire row width), while on medium screens, each column should take up 6 columns (i.e. half the row width).

The first v-col contains the CreateJokeForm component, which displays a form for adding new jokes. The second v-col contains the JokeList component, which is used to display a list of jokes that have been added through the form.

In the script section of the file, we import the CreateJokeForm and JokeList components, and register them as components for use in the template.

This view provides a simple and responsive layout for our app's home page, with the CreateJokeForm and JokeList components displayed side by side on medium screens and stacked on small screens.

Bonus: Layouts & Theming

Layouts

Even though we had no need to adjust our layouts in our current jokes application, layouts are an important concept in Vuetify. They allow us to pre-define reusable layouts for our applications. These could include having a different layout for when users are logged in, and when they are logged out or layouts for different types of users.

In our application, we used the default Layout (src/layouts/default/Default.vue) but Vuetify offers us the flexibility to build different layouts for the different domains in our applications. Vuetify also supports nested layouts. You can learn more about layouts in Vuetify in the official Vuetify documentation.

Theming

If you have specific brand needs for your application. Vuetify has a built-in theming system that allows you to customize the look and feel of your application. You can learn more about theming in the official Vuetify theming documentation.

Conclusion

In this article, we introduced Vuetify, and covered how to set it up with Vue 3. We built a VueJS app that allows us to add and manage jokes. We also discussed how to use various Vuetify components to compose our UI, from v-form for declaring forms to v-row for creating a row/column layout, and v-list for displaying a list of items among others.

With this knowledge, you can start using Vuetify in your Vue 3 projects and create stunning user interfaces. Also, if you'd like to start your own VueJS project but need help with how to structure it or would like to skip the tedious setup steps of setting up a VueJS project, you can use the Vue 3 Starter.dev kit to skip the boilerplate and start building!

Next steps for learning Vuetify and Vue 3 development

Now that you have an understanding of Vuetify, it's time to dive deeper into its features, and explore more advanced use cases. To continue your learning journey, consider the following resources:

  1. Official Vuetify documentation: The Vuetify documentation is an excellent resource for learning about all the features and components Vuetify offers.

  2. Vue 3 documentation: To get the most out of Vuetify, it's essential to have a solid understanding of Vue 3. Read the official Vue 3 documentation and practice building Vue applications.

Happy coding, and have fun exploring the world of Vuetify and Vue 3!

This Dot is a consultancy dedicated to guiding companies through their modernization and digital transformation journeys. Specializing in replatforming, modernizing, and launching new initiatives, we stand out by taking true ownership of your engineering projects.

We love helping teams with projects that have missed their deadlines or helping keep your strategic digital initiatives on course. Check out our case studies and our clients that trust us with their engineering.

You might also like

“Music and code have a lot in common,” freeCodeCamp’s Jessica Wilkins on what the tech community is doing right to onboard new software engineers cover image

“Music and code have a lot in common,” freeCodeCamp’s Jessica Wilkins on what the tech community is doing right to onboard new software engineers

Before she was a software developer at freeCodeCamp, Jessica Wilkins was a classically trained clarinetist performing across the country. Her days were filled with rehearsals, concerts, and teaching, and she hadn’t considered a tech career until the world changed in 2020. > “When the pandemic hit, most of my gigs were canceled,” she says. “I suddenly had time on my hands and an idea for a site I wanted to build.” That site, a tribute to Black musicians in classical and jazz music, turned into much more than a personal project. It opened the door to a whole new career where her creative instincts and curiosity could thrive just as much as they had in music. Now at freeCodeCamp, Jessica maintains and develops the very JavaScript curriculum that has helped her and millions of developers around the world. We spoke with Jessica about her advice for JavaScript learners, why musicians make great developers, and how inclusive communities are helping more women thrive in tech. Jessica’s Top 3 JavaScript Skill Picks for 2025 If you ask Jessica what it takes to succeed as a JavaScript developer in 2025, she won’t point you straight to the newest library or trend. Instead, she lists three skills that sound simple, but take real time to build: > “Learning how to ask questions and research when you get stuck. Learning how to read error messages. And having a strong foundation in the fundamentals” She says those skills don’t come from shortcuts or shiny tools. They come from building. > “Start with small projects and keep building,” she says. “Books like You Don’t Know JS help you understand the theory, but experience comes from writing and shipping code. You learn a lot by doing.” And don’t forget the people around you. > “Meetups and conferences are amazing,” she adds. “You’ll pick up things faster, get feedback, and make friends who are learning alongside you.” Why So Many Musicians End Up in Tech A musical past like Jessica’s isn’t unheard of in the JavaScript industry. In fact, she’s noticed a surprising number of musicians making the leap into software. > “I think it’s because music and code have a lot in common,” she says. “They both require creativity, pattern recognition, problem-solving… and you can really get into flow when you’re deep in either one.” That crossover between artistry and logic feels like home to people who’ve lived in both worlds. What the Tech Community Is Getting Right Jessica has seen both the challenges and the wins when it comes to supporting women in tech. > “There’s still a lot of toxicity in some corners,” she says. “But the communities that are doing it right—like Women Who Code, Women in Tech, and Virtual Coffee—create safe, supportive spaces to grow and share experiences.” She believes those spaces aren’t just helpful, but they’re essential. > “Having a network makes a huge difference, especially early in your career.” What’s Next for Jessica Wilkins? With a catalog of published articles, open-source projects under her belt, and a growing audience of devs following her journey, Jessica is just getting started. She’s still writing. Still mentoring. Still building. And still proving that creativity doesn’t stop at the orchestra pit—it just finds a new stage. Follow Jessica Wilkins on X and Linkedin to keep up with her work in tech, her musical roots, and whatever she’s building next. Sticker illustration by Jacob Ashley....

The Future of Dates in JavaScript: Introducing Temporal cover image

The Future of Dates in JavaScript: Introducing Temporal

The Future of Dates in JavaScript: Introducing Temporal What is Temporaal? Temporal is a proposal currently at stage 3 of the TC39 process. It's expected to revolutionize how we handle dates in JavaScript, which has always been a challenging aspect of the language. But what does it mean that it's at stage 3 of the process? * The specification is complete * It has been reviewed * It's unlikely to change significantly at this point Key Features of Temporal Temporal introduces a new global object with a fresh API. Here are some important things to know about Temporal: 1. All Temporal objects are immutable 2. They're represented in local calendar systems, but can be converted 3. Time values use 24-hour clocks 4. Leap seconds aren't represented Why Do We Need Temporal? The current Date object in JavaScript has several limitations: * No support for time zones other than the user's local time and UTC * Date objects can be mutated * Unpredictable behavior * No support for calendars other than Gregorian * Daylight savings time issues While some of these have workarounds, not all can be fixed with the current Date implementation. Let's see some useful examples where Temporal will improve our lives: Some Examples Creating a day without a time zone is impossible using Date, it also adds time beyond the date. Temporal introduces PlainDate to overcome this. ` But what if we want to add timezone information? Then we have ZonedDateTime for this purpose. The timezone must be added in this case, as it also allows a lot of flexibility when creating dates. ` Temporal is very useful when manipulating and displaying the dates in different time zones. ` Let's try some more things that are currently difficult or lead to unexpected behavior using the Date object. Operations like adding days or minutes can lead to inconsistent results. However, Temporal makes these operations easier and consistent. ` Another interesting feature of Temporal is the concept of Duration, which is the difference between two time points. We can use these durations, along with dates, for arithmetic operations involving dates and times. Note that Durations are serialized using the ISO 8601 duration format ` Temporal Objects We've already seen some of the objects that Temporal exposes. Here's a more comprehensive list. * Temporal * Temporal.Duration` * Temporal.Instant * Temporal.Now * Temporal.PlainDate * Temporal.PlainDateTime * Temporal.PlainMonthDay * Temporal.PlainTime * Temporal.PlainYearMonth * Temporal.ZonedDateTime Try Temporal Today If you want to test Temporal now, there's a polyfill available. You can install it using: ` Note that this doesn't install a global Temporal object as expected in the final release, but it provides most of the Temporal implementation for testing purposes. Conclusion Working with dates in JavaScript has always been a bit of a mess. Between weird quirks in the Date object, juggling time zones, and trying to do simple things like “add a day,” it’s way too easy to introduce bugs. Temporal is finally fixing that. It gives us a clear, consistent, and powerful way to work with dates and times. If you’ve ever struggled with JavaScript dates (and who hasn’t?), Temporal is definitely worth checking out....

Nuxt 3 Demo App with Prerender and SSR cover image

Nuxt 3 Demo App with Prerender and SSR

Introduction The quest for an optimal web application involves numerous factors, such as performance, user experience, and search engine optimization (SEO). Nuxt 3 provides excellent features out-of-the-box that can help you tackle these aspects efficiently. This article will guide you in creating a Nuxt 3 application using Server Side Rendering (SSR) and pre-rendering capabilities. We'll craft an application that offers a seamless user experience, superior performance, and improved SEO. Server Side Rendering in Nuxt 3 Enhancing User Experience and SEO with SSR In the world of web development, Server Side Rendering (SSR) has gained significant traction. It refers to the server rendering the webpage upon each request rather than the client. With SSR, your web page arrives fully formed at the client's doorstep, reducing the time for the first painting. The advantage of SSR extends beyond just performance and user experience. It's also a darling of search engine crawlers, which find it easier to index your website with fully formed page content at the time of their crawl. In simple terms, it's like providing a tour guide to lead the search engine around your website, ensuring they get all the spots! The Power of SSR in Nuxt 3 Nuxt 3 has built-in support for SSR by default. It allows you to optimize your application by loading the data before rendering the page. To take advantage of SSR, you simply build your application as you usually would. In this case, using the fetch() method to load some. ` In this example, the fetchData function fetches the data before rendering the page. The data then gets displayed within the tag. Sidenote, if you wanted to disable SSR in your Nuxt application, you would do so in your nuxt.config.ts file: `` More details on how this works can be found in the rendering modes section in the official Nuxt 3 documentation. Pre-rendering in Nuxt 3 Amplifying Application Performance with Pre-rendering While SSR has its advantages, another superhero in our story is pre-rendering. Pre-rendering refers to the process of generating the static HTML pages of a site in advance. It's like preparing a feast before the guests arrive so you can serve them promptly. Like SSR, pre-rendering enhances SEO, as search engines can index fully rendered pages. Especially for content-heavy applications, pre-rendering can give a turbo boost to performance, leading to better user engagement and retention. Leverage Pre-rendering with Nuxt 3 Nuxt 3 supports SSR and Static Site Generation (SSG), including pre-rendering. To enable prerendering, you need to export your routes in nuxt.config.ts: ` These routes will be pre-rendered during the build phase, allowing for swift navigation. Let's update our application to pre-render the users' list: ` In the nuxt.config.ts, include the users' route for pre-rendering: ` Going beyond with Nuxt 3 While SSR and pre-rendering are significant for performance and SEO, Nuxt 3 offers more advanced features like hot module replacement, Vue 3 integration, improved error handling, and more. Nuxt 3 also has different kinds of rendering modes for different applications; in our SSR case, we used the default Universal rendering mode. Leveraging these features allows you to develop robust, high-performance, and user-friendly applications. Conclusion In this article, we delved into the concepts of SSR and pre-rendering in Nuxt 3. We explored how these techniques contribute to enhancing performance, user experience, and SEO. You can create exceptional web applications by integrating Vue 3's capabilities with Nuxt 3's robust features. A well-structured, performant, and SEO-friendly application not only attract users but also retains them. Embrace the power of Nuxt 3 and Vue 3 in your development journey. Happy coding!...

Understanding Sourcemaps: From Development to Production cover image

Understanding Sourcemaps: From Development to Production

What Are Sourcemaps? Modern web development involves transforming your source code before deploying it. We minify JavaScript to reduce file sizes, bundle multiple files together, transpile TypeScript to JavaScript, and convert modern syntax into browser-compatible code. These optimizations are essential for performance, but they create a significant problem: the code running in production does not look like the original code you wrote. Here's a simple example. Your original code might look like this: ` After minification, it becomes something like this: ` Now imagine trying to debug an error in that minified code. Which line threw the exception? What was the value of variable d? This is where sourcemaps come in. A sourcemap is a JSON file that contains a mapping between your transformed code and your original source files. When you open browser DevTools, the browser reads these mappings and reconstructs your original code, allowing you to debug with variable names, comments, and proper formatting intact. How Sourcemaps Work When you build your application with tools like Webpack, Vite, or Rollup, they can generate sourcemap files alongside your production bundles. A minified file references its sourcemap using a special comment at the end: ` The sourcemap file itself contains a JSON structure with several key fields: ` The mappings field uses an encoding format called VLQ (Variable Length Quantity) to map each position in the minified code back to its original location. The browser's DevTools use this information to show you the original code while you're debugging. Types of Sourcemaps Build tools support several variations of sourcemaps, each with different trade-offs: Inline sourcemaps: The entire mapping is embedded directly in your JavaScript file as a base64 encoded data URL. This increases file size significantly but simplifies deployment during development. ` External sourcemaps: A separate .map file that's referenced by the JavaScript bundle. This is the most common approach, as it keeps your production bundles lean since sourcemaps are only downloaded when DevTools is open. Hidden sourcemaps: External sourcemap files without any reference in the JavaScript bundle. These are useful when you want sourcemaps available for error tracking services like Sentry, but don't want to expose them to end users. Why Sourcemaps During development, sourcemaps are absolutely critical. They will help avoid having to guess where errors occur, making debugging much easier. Most modern build tools enable sourcemaps by default in development mode. Sourcemaps in Production Should you ship sourcemaps to production? It depends. While security by making your code more difficult to read is not real security, there's a legitimate argument that exposing your source code makes it easier for attackers to understand your application's internals. Sourcemaps can reveal internal API endpoints and routing logic, business logic, and algorithmic implementations, code comments that might contain developer notes or TODO items. Anyone with basic developer tools can reconstruct your entire codebase when sourcemaps are publicly accessible. While the Apple leak contained no credentials or secrets, it did expose their component architecture and implementation patterns. Additionally, code comments can inadvertently contain internal URLs, developer names, or company-specific information that could potentially be exploited by attackers. But that’s not all of it. On the other hand, services like Sentry can provide much more actionable error reports when they have access to sourcemaps. So you can understand exactly where errors happened. If a customer reports an issue, being able to see the actual error with proper context makes diagnosis significantly faster. If your security depends on keeping your frontend code secret, you have bigger problems. Any determined attacker can reverse engineer minified JavaScript. It just takes more time. Sourcemaps are only downloaded when DevTools is open, so shipping them to production doesn't affect load times or performance for end users. How to manage sourcemaps in production You don't have to choose between no sourcemaps and publicly accessible ones. For example, you can restrict access to sourcemaps with server configuration. You can make .map accessible from specific IP addresses. Additionally, tools like Sentry allow you to upload sourcemaps during your build process without making them publicly accessible. Then configure your build to generate sourcemaps without the reference comment, or use hidden sourcemaps. Sentry gets the mapping information it needs, but end users can't access the files. Learning from Apple's Incident Apple's sourcemap incident is a valuable reminder that even the largest tech companies can make deployment oversights. But it also highlights something important: the presence of sourcemaps wasn't actually a security vulnerability. This can be achieved by following good security practices. Never include sensitive data in client code. Developers got an interesting look at how Apple structures its Svelte codebase. The lesson is that you must be intentional about your deployment configuration. If you're going to include sourcemaps in production, make that decision deliberately after considering the trade-offs. And if you decide against using public sourcemaps, verify that your build process actually removes them. In this case, the public repo was quickly removed after Apple filed a DMCA takedown. (https://github.com/github/dmca/blob/master/2025/11/2025-11-05-apple.md) Making the Right Choice So what should you do with sourcemaps in your projects? For development: Always enable them. Use fast options, such as eval-source-map in Webpack or the default configuration in Vite. The debugging benefits far outweigh any downsides. For production: Consider your specific situation. But most importantly, make sure your sourcemaps don't accidentally expose secrets. Review your build output, check for hardcoded credentials, and ensure sensitive configurations stay on the backend where they belong. Conclusion Sourcemaps are powerful development tools that bridge the gap between the optimized code your users download and the readable code you write. They're essential for debugging and make error tracking more effective. The question of whether to include them in production doesn't have a unique answer. Whatever you decide, make it a deliberate choice. Review your build configuration. Verify that sourcemaps are handled the way you expect. And remember that proper frontend security doesn't come from hiding your code. Useful Resources * Source map specification - https://tc39.es/ecma426/ * What are sourcemaps - https://web.dev/articles/source-maps * VLQ implementation - https://github.com/Rich-Harris/vlq * Sentry sourcemaps - https://docs.sentry.io/platforms/javascript/sourcemaps/ * Apple DMCA takedown - https://github.com/github/dmca/blob/master/2025/11/2025-11-05-apple.md...

Let's innovate together!

We're ready to be your trusted technical partners in your digital innovation journey.

Whether it's modernization or custom software solutions, our team of experts can guide you through best practices and how to build scalable, performant software that lasts.

Prefer email? hi@thisdot.co