Skip to content

GitHub.Issue reference

Source: src/GitHub/Comment.ts

A GitHub issue or pull request comment.

Comment manages the lifecycle of a single comment on an issue or pull request. Comments are created on the first deploy and updated in place on subsequent deploys when the body changes. By default, comments are never deleted to preserve discussion history — set allowDelete: true to opt in.

Authentication is resolved in order: explicit token prop, GITHUB_ACCESS_TOKEN env var, GITHUB_TOKEN env var. The token needs repo scope for private repositories or public_repo for public ones.

Comment on an Issue

const comment = yield* GitHub.Comment("issue-comment", {
owner: "my-org",
repository: "my-repo",
issueNumber: 123,
body: "This is a comment created by Alchemy!",
});

Comment on a Pull Request

const prComment = yield* GitHub.Comment("pr-comment", {
owner: "my-org",
repository: "my-repo",
issueNumber: 456,
body: "## Deployment Status\n\nSuccessfully deployed to staging!",
});

Deploy with the same logical ID and a different body to update the existing comment in place rather than creating a new one.

const comment = yield* GitHub.Comment("status-comment", {
owner: "my-org",
repository: "my-repo",
issueNumber: 789,
body: "Deployment completed successfully!",
});
const comment = yield* GitHub.Comment("temp-comment", {
owner: "my-org",
repository: "my-repo",
issueNumber: 123,
body: "This comment can be deleted",
allowDelete: true,
});

A common pattern is posting a preview-deployment URL on every pull request. The comment auto-updates on each push because the logical ID stays the same.

if (process.env.PULL_REQUEST) {
yield* GitHub.Comment("preview-comment", {
owner: "my-org",
repository: "my-repo",
issueNumber: Number(process.env.PULL_REQUEST),
body: Output.interpolate`
## Preview Deployed
**URL:** ${website.url}
`,
});
}

Source: src/GitHub/Issue.ts

A GitHub repository issue.

Issue manages the lifecycle of a single issue in a repository. Issues are created on the first deploy and updated in place on subsequent deploys when properties change. By default, issues are retained on destruction to preserve discussion history. Pipe the resource through destroy() to close the issue on destruction instead; its discussion remains on GitHub.

Authentication is resolved via the GitHubCredentials service supplied by GitHub.providers() (env, stored PAT, gh CLI, or OAuth). The token needs repo scope for private repositories or public_repo for public ones.

Create a Basic Issue

const issue = yield* GitHub.Issue("bug-report", {
owner: "my-org",
repository: "my-repo",
title: "Bug: Application crashes on startup",
body: "## Description\n\nThe application crashes when...",
})

Issue with Labels and Assignees

const issue = yield* GitHub.Issue("feature-request", {
owner: "my-org",
repository: "my-repo",
title: "Feature: Add dark mode",
body: "Users have requested...",
labels: ["enhancement", "ui"],
assignees: ["developer1"],
})

Deploy with the same logical ID and different properties to update the existing issue in place rather than creating a new one.

const issue = yield* GitHub.Issue("resolved-bug", {
owner: "my-org",
repository: "my-repo",
title: "Bug: Application crashes on startup",
body: "This has been resolved.",
state: "closed",
})
const issue = yield* GitHub.Issue("v1-task", {
owner: "my-org",
repository: "my-repo",
title: "Implement authentication",
milestone: 1,
})

A common pattern is creating issues to track infrastructure changes or deployment status.

yield* GitHub.Issue("infra-status", {
owner: "my-org",
repository: "my-repo",
title: "Infrastructure Status",
body: Output.interpolate`
## Current Status
**Database:** ${database.endpoint}
**Cache:** ${cache.endpoint}
`,
labels: ["infrastructure"],
})

Source: src/GitHub/Label.ts

A GitHub repository label.

Label manages repository labels for categorizing issues and pull requests. Labels are created on first deploy and updated in place on subsequent deploys when properties change.

Authentication is resolved via the GitHubCredentials service supplied by GitHub.providers() (env, stored PAT, gh CLI, or OAuth). The token needs repo scope for private repositories or public_repo for public ones.

Basic Label

const bug = yield* GitHub.Label("bug", {
owner: "my-org",
repository: "my-repo",
name: "bug",
color: "d73a4a",
description: "Something isn't working",
});

Multiple Labels

yield* GitHub.Label("feature", {
owner: "my-org",
repository: "my-repo",
name: "feature",
color: "a2eeef",
description: "New feature or request",
});
yield* GitHub.Label("documentation", {
owner: "my-org",
repository: "my-repo",
name: "documentation",
color: "0075ca",
description: "Improvements or additions to documentation",
});

Deploy with the same logical ID and different properties to update the existing label in place.

yield* GitHub.Label("priority-high", {
owner: "my-org",
repository: "my-repo",
name: "priority: high",
color: "ff0000",
description: "Updated: Critical issues requiring immediate attention",
});

GitHub uses 6-character hex codes without the # prefix. Common colors:

  • d73a4a - Red (bugs)
  • 0075ca - Blue (documentation)
  • a2eeef - Light blue (features)
  • 7057ff - Purple (good first issue)
  • 008672 - Green (improvement)
  • e4e669 - Yellow (question)
const labels = [
{ name: "bug", color: "d73a4a", description: "Something isn't working" },
{ name: "enhancement", color: "a2eeef", description: "New feature" },
{ name: "documentation", color: "0075ca", description: "Documentation" },
];
for (const { name, color, description } of labels) {
yield* GitHub.Label(name, {
owner: "my-org",
repository: "my-repo",
name,
color,
description,
});
}

Changing the name creates a new label and deletes the old one.

// First deploy creates "wip"
const label = yield* GitHub.Label("work", {
owner: "my-org",
repository: "my-repo",
name: "wip",
color: "fbca04",
});
// Later deploy with same logical ID but different name replaces it
const label = yield* GitHub.Label("work", {
owner: "my-org",
repository: "my-repo",
name: "in-progress",
color: "fbca04",
});
const repo = yield* GitHub.Repository("api", {
owner: "my-org",
name: "api",
autoInit: true,
});
yield* GitHub.Label("bug", {
owner: repo.owner!,
repository: repo.name!,
name: "bug",
color: "d73a4a",
});

Source: src/GitHub/Milestone.ts

A GitHub milestone.

Milestone manages repository milestones for tracking issues and pull requests. Milestones are created on first deploy and updated in place on subsequent deploys when properties change.

Authentication is resolved via the GitHubCredentials service supplied by GitHub.providers() (env, stored PAT, gh CLI, or OAuth). The token needs repo scope for private repositories or public_repo for public ones.

Basic Milestone

const v1 = yield* GitHub.Milestone("v1", {
owner: "my-org",
repository: "my-repo",
title: "v1.0.0",
description: "First stable release",
});

Milestone with Due Date

yield* GitHub.Milestone("sprint-1", {
owner: "my-org",
repository: "my-repo",
title: "Sprint 1",
description: "Complete user authentication",
dueOn: "2026-12-31",
});

Deploy with the same logical ID and different properties to update the existing milestone in place.

yield* GitHub.Milestone("v2", {
owner: "my-org",
repository: "my-repo",
title: "v2.0.0",
description: "Updated: API redesign and performance improvements",
dueOn: "2027-06-30",
});

Close a Milestone

yield* GitHub.Milestone("v1", {
owner: "my-org",
repository: "my-repo",
title: "v1.0.0",
state: "closed",
});

Reopen a Milestone

yield* GitHub.Milestone("v1", {
owner: "my-org",
repository: "my-repo",
title: "v1.0.0",
state: "open",
});

Changing the title creates a new milestone and deletes the old one.

// First deploy creates "Q1 2026"
const milestone = yield* GitHub.Milestone("q1", {
owner: "my-org",
repository: "my-repo",
title: "Q1 2026",
});
// Later deploy with same logical ID but different title replaces it
const milestone = yield* GitHub.Milestone("q1", {
owner: "my-org",
repository: "my-repo",
title: "Q1 2027",
});
import * as Output from "alchemy/Output";
const repo = yield* GitHub.Repository("api", {
owner: "my-org",
name: "api",
autoInit: true,
});
yield* GitHub.Milestone("launch", {
owner: repo.owner!,
repository: Output.map(repo.fullName, (fullName) => fullName.split("/")[1]!),
title: "Initial Launch",
dueOn: "2026-12-31",
});