⚙️ GitHub Actions Generator
Pick a workflow type and triggers from a form to instantly generate YAML you can drop into .github/workflows/. Supports Node.js, Python, PHP, Go, Docker build/push, Pages, Vercel, Netlify, Release, Cron, and Lint workflows.
🔒 About Privacy
- ・YAML is generated entirely in your browser
- ・Branch names, versions and other inputs are never sent to any server
- ・No storage logs, no database
- ・No signup, no login, no payment ever
(click "Generate YAML" above)
📖 Where people get stuck
Choose a workflow type (Node, Python, PHP, Go, Docker, Pages, Vercel, Netlify, Release, Cron or Lint) and its triggers, and this generates YAML you can drop straight into .github/workflows/. Everything runs in the browser and branch names and versions are not transmitted. What it generates is a syntactically valid workflow, not a workflow that will pass in your project — the actual commands for installing dependencies and running tests differ from repository to repository. And what really hurts in CI is not YAML formatting but permissions and time. That is what follows.
| Case | What happens | What to do |
|---|---|---|
| A pull request from a fork gets no secrets | A workflow triggered by pull_request runs with a read-only GITHUB_TOKEN and receives none of the repository secrets when the pull request comes from a fork. That is a deliberate safety measure — otherwise anyone could make your secrets print themselves simply by opening a pull request. The consequence is that a workflow containing a deploy or a coverage upload always fails on pull requests from forks. A dangerous workaround is well known: switching to pull_request_target does deliver the secrets, but that trigger runs with the permissions of the base branch, so checking out and running the pull request code there executes code written by an outsider with your secrets in hand — effectively a repository takeover. |
Split the workflow in two. Run tests and lint on pull_request, which needs no secrets, and deploys on push to main or on release. Pull requests from forks then pass CI normally, and no path exists by which secrets can leave. If you do use pull_request_target, never check out the pull request code — restrict it to things that do not execute code, such as labelling or posting a comment. Alongside this, state permissions: explicitly at the top of every workflow — writing permissions: {contents: read} alone strips write access from that workflow GITHUB_TOKEN. Adding back only the permissions a given job needs is the correct order of operations. |
| Referencing a third-party action by tag | The v1 in uses: some/action@v1 is a branch or tag, that is, a movable reference — if the action author, or whoever takes over that account, changes its contents, your CI runs different code on its next execution. That code has access to the GITHUB_TOKEN and to any secrets you passed to the job. This is not theoretical: popular actions have in fact been compromised and used to harvest secrets. Official actions/* are one thing, but casually referencing a handy little action at @main is not meaningfully different from handing someone write access to your repository. |
Pin third-party actions to a commit SHA — uses: some/action@a1b2c3d4.... A SHA cannot be rewritten, so what runs next is determined. Leave updates to Dependabot: adding package-ecosystem: "github-actions" to .github/dependabot.yml makes it open pull requests that bump the SHA — pinning and updating are not in conflict. Reducing the number of actions is effective too: if an action only copies one file, writing cp under run: removes a dependency. And pass secrets to jobs as narrowly as possible — put them at workflow level as environment variables and every action inside can read them. |
| Cron does not run on time, and stops after 60 days | The schedule trigger has three traps beyond its syntax. Times are always UTC, not your timezone — 0 3 * * * means three in the morning UTC. Runs are not punctual: at busy periods they are delayed by minutes to tens of minutes, and under heavy load a run can be skipped entirely. The top of the hour is the busiest slot, so simply avoiding round times makes things steadier. The third is the one that surprises people most: GitHub automatically disables scheduled workflows in a repository with no commits for 60 days — an email is sent, but if you miss it, discovering months later that nothing has run is an entirely ordinary outcome. |
Write the cron expression in UTC and offset it a few minutes from the round time — 17 3 * * * rather than 0 3 * * *. And always add workflow_dispatch alongside it — being able to trigger it by hand is what lets you test it and re-run it (a workflow you cannot try without waiting for the schedule is itself a source of accidents). The defence against auto-disabling is to be able to notice: have the job notify an external system on success, so that the absence of a notification is detectable — alerting on failure alone cannot detect a job that stopped running. If you need precise timing or high reliability, use a dedicated scheduler rather than the GitHub Actions cron. |
Build cache keys together with the lockfile. If the cache: npm of actions/setup-node or the key of actions/cache does not include a hash of the lockfile, an old cache keeps being restored even after you update dependencies — producing the opaque situation where it is fixed locally but only CI fails, on stale dependencies. Put hashFiles('**/package-lock.json') in the key. Caches are also shared across branches — a poisoned cache spreads to other branches, so when in doubt, rename the key and rebuild it. One more thing: take care not to print secrets into the log. GitHub masks registered secrets automatically, but a transformed value — Base64 encoded, embedded in JSON, or partially extracted — is not masked. Enabling set -x or debug output records the whole command line — and on a public repository, anyone can read the Actions log.
📖 How to Use
-
1
Pick a workflow typeSelect from Node.js, Python, PHP, Go, Docker, Pages, Vercel, Netlify, Release, Cron, or Lint.
-
2
Set triggers and branchToggle push, pull_request, schedule, or workflow_dispatch and enter the target branch or cron expression.
-
3
Generate YAML and commit itClick Generate YAML, then copy or download. Drop the file under .github/workflows/ and push to enable it.
❓ Frequently Asked Questions
How do I configure the secrets it references?
Which action versions are pinned?
Can I use this with self-hosted runners?
🔗 Related Tools
🐛 Found a bug or issue with this tool?
Free to use, no signup. Even just the steps to reproduce are helpful. Reports go directly to the operator and help us fix issues.
Thanks for your report!
Your report has been delivered to the operator and will be used to improve the tool.