> ## Documentation Index
> Fetch the complete documentation index at: https://site.aspect.build/llms.txt
> Use this file to discover all available pages before exploring further.

# Bazel can write to the source folder!

> Bazel can write to the source folder for specific needs, using `bazel run` and `bazel test` to maintain consistency

export const BlogPost = ({title, date, authors, tags, image, children}) => {
  const tagList = tags ? tags.split(", ").filter(Boolean) : [];
  const tagSlug = t => t.toLowerCase().replace(/&/g, "").replace(/\+/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
  const formattedDate = date ? new Date(date + "T00:00:00").toLocaleDateString("en-US", {
    year: "numeric",
    month: "long",
    day: "numeric"
  }) : "";
  return <section className="w-full flex justify-center px-4 py-12 md:py-16">
      <div style={{
    maxWidth: "800px",
    width: "100%"
  }}>
        {image && (typeof image === "string" ? <img noZoom src={image} alt={title} className="w-full rounded-xl mb-8" style={{
    maxHeight: "400px",
    objectFit: "cover"
  }} /> : <div className="blog-post-hero-image">{image}</div>)}
        <h1 className="text-3xl md:text-4xl font-bold text-zinc-900 dark:text-white">
          {title}
        </h1>
        <div className="flex flex-wrap items-center gap-3 mt-4 text-sm text-zinc-500 dark:text-zinc-400">
          {authors && <span>{authors}</span>}
          {authors && formattedDate && <span>·</span>}
          {formattedDate && <span>{formattedDate}</span>}
        </div>
        {tagList.length > 0 && <div className="flex flex-wrap gap-2 mt-3">
            {tagList.map(tag => <a key={tag} href={"/blog/tags/" + tagSlug(tag)} className="px-2 py-0.5 rounded-full text-xs bg-zinc-100 dark:bg-zinc-800 text-zinc-600 dark:text-zinc-400 hover:bg-blue-100 dark:hover:bg-blue-900/40 hover:text-blue-700 dark:hover:text-blue-300 transition">
                {tag}
              </a>)}
          </div>}
        <hr className="my-8 border-zinc-200 dark:border-zinc-700" />
        <div className="prose dark:prose-invert max-w-none">{children}</div>
      </div>
    </section>;
};

export const MarketingPage = () => <div className="marketing-page-marker" style={{
  display: "none"
}} />;

export const Section = ({children, className = "", gray = false, dark = false, id}) => <section id={id} className={`w-full flex justify-center px-4 py-16 md:py-24 ${gray ? "bg-gray-50 dark:bg-zinc-900" : dark ? "bg-zinc-900 dark:bg-zinc-950" : ""} ${className}`}>
    <div className="w-full" style={{
  maxWidth: "1140px"
}}>
      {children}
    </div>
  </section>;

<MarketingPage />

<BlogPost title="Bazel can write to the source folder!" date="2021-11-10" authors="Alex Eagle" tags="Bazel">
  <img noZoom src="https://mintcdn.com/aspectbuild/x1L7Iep716jCyJVo/images/blog/stock/laptop-writing.jpg?fit=max&auto=format&n=x1L7Iep716jCyJVo&q=85&s=fa02efdb4b199fc3c4f14849af5c40c0" alt="" className="blog-post-cover" width="800" height="533" data-path="images/blog/stock/laptop-writing.jpg" />

  Bazel is Google's open-sourced build tool. When used internally at Google, it comes along with a bunch of idioms which Googlers naturally take for granted, and associate with Bazel. These can accidentally become part of the accepted dogma around Bazel migration.

  Most frequently, the accident I see is a false perception "Bazel cannot write to the source folder, so you can no longer check in generated files, nor have them in the sources but ignored from VCS".

  ## Typically you shouldn't do it

  Intermediate outputs in Bazel are meant to be used directly as inputs to another target in the build. For example, if you generate language-specific client stubs from a `.proto` file, those stay in the `bazel-out` folder and a later compiler step should be configured to read them from there.

  However there are plenty of cases where outputs do need to go in the source folder:

  * workaround for an editor plugin that only knows to read in the source folder and can't be configured to look in bazel-out

  * "golden" or "snapshot" files used for tests

  * generated documentation that's checked in next to sources

  * files that you need to be able to search or browse from your version control GUI

  ## Yes you can do it

  If you restrict yourself to only `bazel build` and `bazel test`, then it's true that neither of these commands can mutate the source tree. Bazel is strictly a transform tool from the sources to its own bazel-out folder. However, `bazel run` has no such limitation, and in fact always sets an environment variable `BUILD_WORKSPACE_DIRECTORY` which makes it easy to find your sources and modify them.

  This leads us to the "Write to Sources" pattern for Bazel. We'll use `bazel run` to make the updates, and `bazel test` to make sure developers don't allow the file in the source folder to drift from what Bazel generates.

  Note that this pattern does have one downside, compared with build tools that allow a build to directly output into the source tree. Until you run the tests, it's possible that you're working against an out-of-date file in the source folder. This could mean you spend some time developing, only to find on CI that the generated file needs to be updated, and then after updating it, you have to make some fixes to the code you wrote.

  The easiest way to use this pattern is with rules that already exist for this purpose. Aspect has a [`write_source_files`](https://registry.bazel.build/modules/bazel_lib#lib-write_source_files-bzl) rule, and another option is [`updatesrc`](https://github.com/cgrindel/bazel-starlib/tree/main/updatesrc) from Chuck Grindel.

  You can also assemble the parts yourself, directly in a `BUILD.bazel` file. Here's the basic recipe, which I've adapted to many scenarios. For example, many of the core Bazel rulesets now use this pattern to keep their generated API markdown files in sync with the sources.

  ```python theme={null}
  load("@bazel_skylib//rules:diff_test.bzl", "diff_test")
  load("@bazel_skylib//rules:write_file.bzl", "write_file")

  # Config:
  # Map from some source file to a target that produces it.
  # This recipe assumes you already have some such targets.
  _GENERATED = {
      "some-source": "//:generated.txt",
      # ...
  }

  # Create a test target for each file that Bazel should
  # write to the source tree.
  [
      diff_test(
          name = "check_" + k,
          # Make it trivial for devs to understand that if
          # this test fails, they just need to run the updater
          # Note, you need bazel-skylib version 1.1.1 or greater
          # to get the failure_message attribute
          failure_message = "Please run:  bazel run //:update",
          file1 = k,
          file2 = v,
      )
      for [k, v] in _GENERATED.items()
  ]

  # Generate the updater script so there's only one target for devs to run,
  # even if many generated files are in the source folder.
  write_file(
      name = "gen_update",
      out = "update.sh",
      content = [
          # This depends on bash, would need tweaks for Windows
          "#!/usr/bin/env bash",
          # Bazel gives us a way to access the source folder!
          "cd $BUILD_WORKSPACE_DIRECTORY",
      ] + [
          # Paths are now relative to the workspace.
          # We can copy files from bazel-bin to the sources
          "cp -fv bazel-bin/{1} {0}".format(
              k,
              # Convert label to path
              v.replace(":", "/"),
          )
          for [k, v] in _GENERATED.items()
      ],
  )

  # This is what you can `bazel run` and it can write to the source folder
  sh_binary(
      name = "update",
      srcs = ["update.sh"],
      data = _GENERATED.values(),
  )
  ```

  You may want to tweak the recipe, for example if the output files are markdown I'll append ".md" to the keys. If your files follow a convention you might be able to configure it with just a list rather than a dictionary.
</BlogPost>
