PageSourceSearch

https://projen.io/assets/js/7a0124d5.8e5ad8a4.js

js projen.io collected 2026-10-02 05:18:51 UTC 23,581 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([["5342"],{4300(e,s,n){n.r(s),n.d(s,{metadata:()=>i,default:()=>h,frontMatter:()=>t,contentTitle:()=>o,toc:()=>c,assets:()=>l});var i=JSON.parse('{"id":"publishing/releases-and-versioning","title":"Releases and Versioning","description":"Projen takes care of managing versioning and releases of your project.","source":"@site/../docs/publishing/releases-and-versioning.md","sourceDirName":"publishing","slug":"/publishing/releases-and-versioning","permalink":"/docs/publishing/releases-and-versioning","draft":false,"unlisted":false,"editUrl":"https://github.com/projen/projen/tree/main/docusaurus/../docs/publishing/releases-and-versioning.md","tags":[],"version":"current","sidebarPosition":4,"frontMatter":{"sidebar_position":4},"sidebar":"docsSidebar","previous":{"title":"Trusted Publishers","permalink":"/docs/publishing/trusted-publishing"},"next":{"title":"AWS Cloud Projects","permalink":"/docs/integrations/aws/"}}'),r=n(4848),a=n(8453);let t={sidebar_position:4},o="Releases and Versioning",l={},c=[{value:"Initial development phase",id:"initial-development-phase",level:2},{value:"Major Versions",id:"major-versions",level:2},{value:"Prerelease Versions",id:"prerelease-versions",level:2},{value:"Breaking Changes",id:"breaking-changes",level:2},{value:"Release Branches",id:"release-branches",level:2},{value:"Release Triggers",id:"release-triggers",level:2},{value:"Scheduled Releases",id:"scheduled-releases",level:2},{value:"Selective Releases",id:"selective-releases",level:2},{value:"How the <code>bump</code> task works",id:"how-the-bump-task-works",level:3},{value:"Manual Releases",id:"manual-releases",level:2},{value:"Publishing modules for manual releases",id:"publishing-modules-for-manual-releases",level:3},{value:"FAQ",id:"faq",level:2},{value:"How can I force a different version?",id:"how-can-i-force-a-different-version",level:3},{value:"Can I change the format of the release tag?",id:"can-i-change-the-format-of-the-release-tag",level:3},{value:"Why is the version in <code>package.json</code> set to <code>0.0.0</code>?",id:"why-is-the-version-in-packagejson-set-to-000",level:3},{value:"Can I do a manual one-off prerelease?",id:"can-i-do-a-manual-one-off-prerelease",level:3}];function d(e){let s={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,a.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(s.header,{children:(0,r.jsx)(s.h1,{id:"releases-and-versioning",children:"Releases and Versioning"})}),"\n",(0,r.jsx)(s.p,{children:"Projen takes care of managing versioning and releases of your project."}),"\n",(0,r.jsxs)(s.p,{children:["The release model is based on (scaled) ",(0,r.jsx)(s.a,{href:"https://trunkbaseddevelopment.com/",children:"trunk-based development"})," and relies on ",(0,r.jsx)(s.a,{href:"https://www.conventionalcommits.org/en/v1.0.0/",children:"Conventional Commits"})," and ",(0,r.jsx)(s.a,{href:"https://semver.org/",children:"Semantic Versioning"}),"\nto automatically determine the next version for every release."]}),"\n",(0,r.jsxs)(s.p,{children:["This means that commits to the default branch (",(0,r.jsx)(s.code,{children:"main"}),") are considered ready for production and by default every commit will be released and published to package managers (see ",(0,r.jsx)(s.a,{href:"#release-triggers",children:"Release Triggers"})," for additional information on this behavior)."]}),"\n",(0,r.jsx)(s.h2,{id:"initial-development-phase",children:"Initial development phase"}),"\n",(0,r.jsxs)(s.p,{children:["New projects start with version ",(0,r.jsx)(s.code,{children:"0.0.0"}),".\nAnything may change at any time and public APIs should not be considered stable.\nCommits marked as a breaking change will increase the ",(0,r.jsx)(s.em,{children:"minor"})," version. All other commits will increase the ",(0,r.jsx)(s.em,{children:"patch"})," version."]}),"\n",(0,r.jsxs)(s.p,{children:["Projen will ",(0,r.jsx)(s.strong,{children:"never"})," release ",(0,r.jsx)(s.code,{children:"v1.0.0"})," without your intervention. Once the project is ready, you have to make a one-time change to bump the major version."]}),"\n",(0,r.jsxs)(s.p,{children:["Before the release and versioning support will work, an initial tag ",(0,r.jsx)(s.strong,{children:"MUST"})," exist in the git repository for the project.\nThe tag ",(0,r.jsx)(s.strong,{children:"MUST"})," conform to ",(0,r.jsx)(s.a,{href:"https://semver.org/",children:"Semantic Versioning"})," conventions.\nFor example, find an appropriate commit on the ",(0,r.jsx)(s.code,{children:"main"})," branch of the git repository and run command:"]}),"\n",(0,r.jsx)(s.pre,{children:(0,r.jsx)(s.code,{className:"language-bash",children:"git tag v0.0.0 <commitId>\n"})}),"\n",(0,r.jsxs)(s.p,{children:["Use the ",(0,r.jsx)(s.code,{children:"git log --oneline"})," command to list commits to select from."]}),"\n",(0,r.jsx)(s.p,{children:"Whatever initial semver tag is specified, the release and versioning support will calculate the next semantic version to use based on this tag."}),"\n",(0,r.jsx)(s.h2,{id:"major-versions",children:"Major Versions"}),"\n",(0,r.jsxs)(s.p,{children:["To bump the major version for the default branch, set the ",(0,r.jsx)(s.code,{children:"majorVersion"})," option to the desired version and push the change.\nFor example:"]}),"\n",(0,r.jsx)(s.pre,{children:(0,r.jsx)(s.code,{className:"language-js",children:"majorVersion: 1\n"})}),"\n",(0,r.jsxs)(s.p,{children:["For major versions 1 and above, if a release includes ",(0,r.jsx)(s.code,{children:"fix"})," commits ",(0,r.jsx)(s.em,{children:"only"}),", it will increase the ",(0,r.jsx)(s.em,{children:"patch"})," version.\nIf a release includes any ",(0,r.jsx)(s.code,{children:"feat"})," commits, then the new version will be a ",(0,r.jsx)(s.em,{children:"minor"})," version."]}),"\n",(0,r.jsx)(s.h2,{id:"prerelease-versions",children:"Prerelease Versions"}),"\n",(0,r.jsxs)(s.p,{children:["To release prerelease versions from the main branch, set the ",(0,r.jsx)(s.code,{children:"prerelease"})," option to the desired prerelease prefix.\nFor example:"]}),"\n",(0,r.jsx)(s.pre,{children:(0,r.jsx)(s.code,{className:"language-js",children:"prerelease: 'beta'\n"})}),"\n",(0,r.jsx)(s.p,{children:"You can also use this with release branches or manual releases (see example below)."}),"\n",(0,r.jsx)(s.h2,{id:"breaking-changes",children:"Breaking Changes"}),"\n",(0,r.jsxs)(s.p,{children:["Conventional Commits allows changes to be marked as breaking by appending a ",(0,r.jsx)(s.code,{children:"!"})," after the type/scope in the commit message or adding a ",(0,r.jsx)(s.code,{children:"BREAKING CHANGE:"})," footer (",(0,r.jsx)(s.a,{href:"https://www.conventionalcommits.org/en/v1.0.0/#examples",children:"see examples"}),")."]}),"\n",(0,r.jsxs)(s.p,{children:["If a release includes breaking changes and the major version was not explicitly updated at the same time, ",(0,r.jsx)(s.strong,{children:"the release will fail"}),"."]}),"\n",(0,r.jsxs)(s.p,{children:["If you rather want to automatically release major versions,\nuse ",(0,r.jsx)(s.code,{children:"minMajorVersion"})," instead of ",(0,r.jsx)(s.code,{children:"majorVersion"})," and breaking changes will now increase the major version:"]}),"\n",(0,r.jsx)(s.pre,{children:(0,r.jsx)(s.code,{className:"language-js",children:"minMajorVersion: 1\n"})}),"\n",(0,r.jsxs)(s.p,{children:["In the initial development phase of major version zero, breaking changes will never fail the release and instead increase the ",(0,r.jsx)(s.em,{children:"minor"})," version (see above)."]}),"\n",(0,r.jsx)(s.h2,{id:"release-branches",children:"Release Branches"}),"\n",(0,r.jsxs)(s.p,{children:["You can release multiple major versions from different branches at the same time through the ",(0,r.jsx)(s.code,{children:"releaseBranches"})," option.\nA separate workflow will be created for each release branch to publish the commits to this branch."]}),"\n",(0,r.jsx)(s.p,{children:"Each release branch must be associated with a different version."}),"\n",(0,r.jsxs)(s.p,{children:["Normally it is sufficient to specify only ",(0,r.jsx)(s.code,{children:"majorVersion"}),". If fixes to an earlier minor version should be released, ",(0,r.jsx)(s.code,{children:"minorVersion"})," can also be specified."]}),"\n",(0,r.jsx)(s.pre,{children:(0,r.jsx)(s.code,{className:"language-js",children:"releaseBranches: {\n  '2.0': {\n    majorVersion: 2,\n    minorVersion: 0,\n  },\n  '2.x': {\n    majorVersion: 2,\n  },\n  '3.x': {\n    majorVersion: 3,\n    prerelease: 'beta',\n  },\n}\n"})}),"\n",(0,r.jsx)(s.h2,{id:"release-triggers",children:"Release Triggers"}),"\n",(0,r.jsxs)(s.p,{children:["If the project type supports it, then you can specify a ",(0,r.jsx)(s.code,{children:"releaseTrigger"}
1),". You can use this to control whether\nor not your releases are automated as well as any unique artifacts associated with releases such as project-level\nchangelogs."]}),"\n",(0,r.jsxs)(s.p,{children:["The default setting for ",(0,r.jsx)(s.code,{children:"releaseTrigger"})," is ",(0,r.jsx)(s.code,{children:"ReleaseTrigger.continuous()"}),".  This setting implies that any commit\nto the ",(0,r.jsx)(s.code,{children:"main"})," branch will result in a release being created.  However, this presumes that GitHub and GitHub actions\nare being used and that the carrying out of the release activity will take place within a GitHub action (see ",(0,r.jsx)(s.code,{children:".github/workflows/release.yml"}),"\nto understand this behavior). Running ",(0,r.jsx)(s.code,{children:"pnpm release"})," on a locally cloned repository with this ",(0,r.jsx)(s.code,{children:"releaseTrigger"})," setting\n",(0,r.jsx)(s.strong,{children:"will"})," create release-related artifacts in the ",(0,r.jsx)(s.code,{children:"dist"})," folder, but ",(0,r.jsx)(s.strong,{children:"will not"})," update the git repository with\nany tag-related information, nor will it update a ",(0,r.jsx)(s.code,{children:"CHANGELOG.md"})," file in the local repository (see ",(0,r.jsx)(s.a,{href:"#manual-releases",children:"Manual Releases"}),"\nfor additional information)."]}),"\n",(0,r.jsx)(s.h2,{id:"scheduled-releases",children:"Scheduled Releases"}),"\n",(0,r.jsx)(s.p,{children:"This setting relies on GitHub and GitHub actions being used. Releases will be created on the CRON-based schedule indicated."}),"\n",(0,r.jsx)(s.pre,{children:(0,r.jsx)(s.code,{className:"language-js",children:"releaseTrigger: ReleaseTrigger.scheduled({ schedule: '0 17 * * *' }),\n"})}),"\n",(0,r.jsx)(s.h2,{id:"selective-releases",children:"Selective Releases"}),"\n",(0,r.jsx)(s.p,{children:"It is possible to only bump the version on a subset of commits.\nFor example you could only release a new version for every feature and fix that was added to the repo."}),"\n",(0,r.jsx)(s.pre,{children:(0,r.jsx)(s.code,{className:"language-js",children:"releasableCommits: ReleasableCommits.featuresAndFixes(),\n"})}),"\n",(0,r.jsx)(s.p,{children:"This check only runs according to the release trigger, but serves as an additional check to not create unnecessary releases."}),"\n",(0,r.jsxs)(s.p,{children:["A custom check can be implemented ",(0,r.jsx)(s.code,{children:"ReleasableCommits.exec()"}),".\nThis command should return a list of commit hashes that are considered releasable.\nI.e. to not not bump the version, the command must print nothing and exit successfully."]}),"\n",(0,r.jsx)(s.pre,{children:(0,r.jsx)(s.code,{className:"language-js",children:'releasableCommits: ReleasableCommits.exec("./custom-script.sh"),\n'})}),"\n",(0,r.jsxs)(s.h3,{id:"how-the-bump-task-works",children:["How the ",(0,r.jsx)(s.code,{children:"bump"})," task works"]}),"\n",(0,r.jsxs)(s.p,{children:["The ",(0,r.jsx)(s.code,{children:"bump"})," task decides the next version and writes the release artifacts. It\nruns as a pipeline of steps, where each step passes its result to later steps\nthrough an environment variable, using the task step\n",(0,r.jsx)(s.a,{href:"/docs/concepts/tasks#capturing-a-steps-output",children:(0,r.jsx)(s.code,{children:"outputEnv"})})," option. Two of the\nsteps ",(0,r.jsx)(s.code,{children:"spawn"})," standalone tasks, so you can run and configure them on their own."]}),"\n",(0,r.jsx)(s.p,{children:"The steps, in order:"}),"\n",(0,r.jsxs)(s.ol,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:(0,r.jsx)(s.code,{children:"resolve-latest-tag"})})," (builtin) \u2014 finds the latest release tag for the\ncurrent branch and seeds the version file with the current version. It\noutputs the tag into ",(0,r.jsx)(s.code,{children:"LATEST_TAG"}),", which is empty on a first release (no tag\nexists yet)."]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:(0,r.jsx)(s.code,{children:"bump:releasable-commits"})})," (spawned task) \u2014 runs your ",(0,r.jsx)(s.code,{children:"releasableCommits"}),"\ncommand (by default, every commit since ",(0,r.jsx)(s.code,{children:"$LATEST_TAG"}),") and outputs the\nmatching commits into ",(0,r.jsx)(s.code,{children:"RELEASABLE_COMMITS"}),". It is skipped on a first release,\nsince there is no tag to diff against."]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:(0,r.jsx)(s.code,{children:"suggest-version-bump"})})," (builtin) \u2014 reads ",(0,r.jsx)(s.code,{children:"RELEASABLE_COMMITS"})," and the\ncommit history to derive the bump implied by the commits\n(",(0,r.jsx)(s.code,{children:"major"}),"/",(0,r.jsx)(s.code,{children:"minor"}),"/",(0,r.jsx)(s.code,{children:"patch"}),"/",(0,r.jsx)(s.code,{children:"none"}),") and outputs it into ",(0,r.jsx)(s.code,{children:"SUGGESTED_BUMP"}),"."]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:(0,r.jsx)(s.code,{children:"bump:next-version"})})," (spawned task, only present when ",(0,r.jsx)(s.code,{children:"nextVersionCommand"}),"\nis set) \u2014 runs your command with ",(0,r.jsx)(s.code,{children:"$VERSION"}),", ",(0,r.jsx)(s.code,{children:"$LATEST_TAG"})," and\n",(0,r.jsx)(s.code,{children:"$SUGGESTED_BUMP"})," available, and outputs its decision into ",(0,r.jsx)(s.code,{children:"BUMP_TYPE"}),",\noverriding the suggestion."]}),"\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.strong,{children:(0,r.jsx)(s.code,{children:"apply-version-bump"})})," (builtin) \u2014 uses ",(0,r.jsx)(s.code,{children:"BUMP_TYPE"})," if set, otherwise\n",(0,r.jsx)(s.code,{children:"SUGGESTED_BUMP"}),", invokes ",(0,r.jsx)(s.code,{children:"commit-and-tag-version"}),", and writes the resolved\nversion and tag into the artifacts directory."]}),"\n"]}),"\n",(0,r.jsxs)(s.p,{children:["Because each step reads what it needs from the environment the previous steps\nleft behind, there is no shared state file: the current version is read back\nfrom the version file that ",(0,r.jsx)(s.code,{children:"resolve-latest-tag"})," seeds, and a first release is\nsignalled by an empty ",(0,r.jsx)(s.code,{children:"LATEST_TAG"}),"."]}),"\n",(0,r.jsxs)(s.p,{children:[(0,r.jsx)(s.code,{children:"bump:releasable-commits"})," and ",(0,r.jsx)(s.code,{children:"bump:next-version"})," are ordinary tasks. You can\nrun them directly to inspect what they do (e.g. ",(0,r.jsx)(s.code,{children:"projen bump:releasable-commits"}),")\nand configure each independently, including its shell \u2014 useful when a command\nrelies on bas
1h-specific syntax:"]}),"\n",(0,r.jsx)(s.pre,{children:(0,r.jsx)(s.code,{className:"language-ts",children:'import { TaskShell } from "projen";\n\nproject.tasks.tryFind("bump:next-version")?.shell = TaskShell.bash();\n'})}),"\n",(0,r.jsx)(s.h2,{id:"manual-releases",children:"Manual Releases"}),"\n",(0,r.jsx)(s.p,{children:"If you don't want projen to automatically release your project, you can configure a manual release trigger:"}),"\n",(0,r.jsx)(s.pre,{children:(0,r.jsx)(s.code,{className:"language-js",children:"releaseTrigger: ReleaseTrigger.manual(),\n"})}),"\n",(0,r.jsxs)(s.p,{children:["This will create a ",(0,r.jsx)(s.code,{children:"release"})," task. Run it locally (",(0,r.jsx)(s.code,{children:"projen release"}),") to cut a release. It will build the project and create releasable artifacts inside the ",(0,r.jsx)(s.code,{children:"dist"})," directory."]}),"\n",(0,r.jsxs)(s.p,{children:["It will also trigger a ",(0,r.jsx)(s.code,{children:"publish:git"})," task. This task does\nmanage a project-level changelog, commit any changes, tag the release (adds a git tag to the commit used\nto update the ",(0,r.jsx)(s.code,{children:"CHANGELOG.md"})," file), and push any commits and tags to the remote repository."]}),"\n",(0,r.jsxs)(s.p,{children:["The command used for pushing can be customized by specifying\n",(0,r.jsx)(s.code,{children:"gitPushCommand"}),". Set to an empty string to disable pushing entirely.\nIf working completely local, setting ",(0,r.jsx)(s.code,{children:"gitPushCommand"})," to an empty string ( ",(0,r.jsx)(s.code,{children:"''"})," )\nresults in the local git repository getting appropriate tags added."]}),"\n",(0,r.jsxs)(s.p,{children:["Note that setting ",(0,r.jsx)(s.code,{children:"releaseTrigger"})," to ",(0,r.jsx)(s.code,{children:"ReleaseTrigger.manual()"})," also has the side-effect of ",(0,r.jsx)(s.strong,{children:"removing"}),"\nthe GitHub action workflow related to release processing. There is no ",(0,r.jsx)(s.code,{children:".github/workflows/release.yml"})," file\ncreated for the repository."]}),"\n",(0,r.jsx)(s.h3,{id:"publishing-modules-for-manual-releases",children:"Publishing modules for manual releases"}),"\n",(0,r.jsxs)(s.p,{children:["With manual releases, projen will ",(0,r.jsx)(s.em,{children:"not"})," automatically publish packages to their respective package repositories.\nYou are expected to publish release artifacts from the ",(0,r.jsx)(s.code,{children:"dist"})," directory manually."]}),"\n",(0,r.jsxs)(s.p,{children:["Please note that the repository itself will ",(0,r.jsx)(s.strong,{children:"not"})," be a releasable state. Publishing anything else but the release artifacts from ",(0,r.jsx)(s.code,{children:"dist"}),", will fail."]}),"\n",(0,r.jsx)(s.p,{children:"For example in a Node.js project, you might run:"}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"projen release"})," ",(0,r.jsx)(s.em,{children:"(runs tests & builds a releasable artifact)"})]}),"\n",(0,r.jsx)(s.li,{children:(0,r.jsx)(s.code,{children:"npm publish dist/js/my-package-1.2.3.tgz"})}),"\n"]}),"\n",(0,r.jsx)(s.p,{children:"Or for a multi language jsii project, the necessary steps could look something like:"}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsx)(s.li,{children:(0,r.jsx)(s.code,{children:"projen release"})}),"\n",(0,r.jsx)(s.li,{children:(0,r.jsx)(s.code,{children:"npx -p publib@latest publib-npm"})}),"\n",(0,r.jsx)(s.li,{children:(0,r.jsx)(s.code,{children:"npx -p publib@latest publib-pypi"})}),"\n",(0,r.jsx)(s.li,{children:(0,r.jsx)(s.code,{children:"npx -p publib@latest publib-nuget"})}),"\n"]}),"\n",(0,r.jsx)(s.p,{children:"It is also your responsibility to ensure credentials are setup and available for each package repository published to."}),"\n",(0,r.jsx)(s.h2,{id:"faq",children:"FAQ"}),"\n",(0,r.jsx)(s.h3,{id:"how-can-i-force-a-different-version",children:"How can I force a different version?"}),"\n",(0,r.jsx)(s.p,{children:"You may be adopting projen in a project that has already been published to previous versions.\nProjen uses tags to determine the version to start with before bumping according to the rules previously mentioned."}),"\n",(0,r.jsxs)(s.p,{children:["You can force the base version number by adding a tag to your repo. For example, if the latest version of your project is 1.2.3, then add a tag to your main branch of ",(0,r.jsx)(s.code,{children:"v1.2.3"}),".\nThe next time the release workflow runs, it will bump from version 1.2.3.\nAs explained above, this is based on the conventional commits so the next release will either be 1.2.4, 1.3.0, or 2.0.0 on a breaking change."]}),"\n",(0,r.jsx)(s.h3,{id:"can-i-change-the-format-of-the-release-tag",children:"Can I change the format of the release tag?"}),"\n",(0,r.jsx)(s.p,{children:"Yes, it is possible to change the tag prefix:"}),"\n",(0,r.jsx)(s.pre,{children:(0,r.jsx)(s.code,{className:"language-js",children:"releaseTagPrefix: 'stable/'\n"})}),"\n",(0,r.jsxs)(s.p,{children:["Please note that this also changes the behavior of finding existing tags and projen will now be looking for tags like ",(0,r.jsx)(s.code,{children:"stable/1.2.3"})," to determine the current version.\nIf you are migrating to a new tag format, make sure to re-tag at least the current version with the new format."]}),"\n",(0,r.jsxs)(s.p,{children:["The default prefix for release tags is ",(0,r.jsx)(s.code,{children:"v*"}),". So if ",(0,r.jsx)(s.code,{children:"releaseTagPrefix"})," is not defined in your ",(0,r.jsx)(s.code,{children:".projenrc.js"})," configuration you must define your tags as ",(0,r.jsx)(s.code,{children:"v1.0.0"}),", ",(0,r.jsx)(s.code,{children:"v2.0.0.0"})," and so on."]}),"\n",(0,r.jsxs)(s.h3,{id:"why-is-the-version-in-packagejson-set-to-000",children:["Why is the version in ",(0,r.jsx)(s.code,{children:"package.json"})," set to ",(0,r.jsx)(s.code,{children:"0.0.0"}),"?"]}),"\n",(0,r.jsxs)(s.p,{children:["Projen uses tags to keep track of the current version of the project.\nWhile Node.js packages natively track theirs versions in ",(0,r.jsx)(s.code,{children:"package.json"}),", not all languages supported by projen provide a mechanism like this.\nConsequently projen uses git tags as a mechanism that is independent of any target language.\nTo convey this message, the version in ",(0,r.jsx)(s.code,{children:"package.json"})," is kept at ",(0,r.jsx)(s.code,{children:"0.0.0"}),"."]}),"\n",(0,r.jsxs)(s.p,{children:["Additionally, Node.js packages are often published directly by running ",(0,r.jsx)(s.code,{children:"npm publish"})," in the root of the repository.\nThis does not work in projen.\nInstead, projen requires you to run ",(0,r.jsx)(s.code,{children:"projen release"})," to create releasable artifacts and manually publish these artifacts."]}),"\n",(0,r.jsx)(s.h3,{id:"can-i-do-a-manual-one-off-prerelease",children:"Can I do a manual one-off prerelease?"}),"\n",(0,r.jsxs)(s.p,{children:["If you wanted to generate a manual prerelease you can set the ",(0,r.jsx)(s.code,{children:"PRERELEASE"})," environment variable."]}),"\n",(0,r.jsx)(s.p,{children:"For example in a Node.js project, you might run:"}),"\n",(0,r.jsxs)(s.ul,{children:["\n",(0,r.jsxs)(s.li,{children:[(0,r.jsx)(s.code,{children:"PRERELEASE=beta projen release"})," ",(0,r.jsx)(s.em,{children:"(runs tests & builds a releasable artifact)"})]}),"\n",(0,r.jsx)(s.li,{children:(0,r.jsx)(s.code,{children:"npm publish dist/js/my-package-1.2.3-beta.0.tgz"})}),"\n"]}),"\n",(0,r.jsxs)(s.p,{children:["Make sure to also read the ",(0,r.jsx)(s.a,{href:"#manual-releases",children:"Manual Releases"})," section above."]})]})}function h(e={}){let{wrapper:s}={...(0,a.R)(),...e.components};return s?(0,r.jsx)(s,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},8453(e,s,n){n.d(s,{R:()=>t,x:()=>o});var i=n(6540);let r={},a=i.createContext(r);function t(e){let s=i.useContext(a);return i.useMemo(function(){return"function"==typeof e?e(s):{...s,...e}},[s,e])}function o(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:t(e.components),i.createElement(a.Provider,{value:s},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.