May 21, 2026·6 min read·engineeringgoapimodulestooling

The pkg.go.dev API makes package identity explicit

The new metadata API distinguishes package discovery from unambiguous module and version selection. Its beta contract gives tool builders structured results while leaving important decisions with the client.

The pkg.go.dev API announcement, published on May 21, introduces programmatic access to package and module metadata. The service uses GET requests under /v1beta. Its endpoints include search and symbol queries as well as module versions, importers, and vulnerability information. This gives tool authors a documented alternative to extracting information from pages intended for human readers.

The decision I find most useful is how the API handles an ambiguous package path. It asks the client to identify the module when more than one module can provide that path. The announcement contrasts this with the website's automatic choice of the longest matching module path. An automated tool needs to retain that distinction because a plausible documentation result is not sufficient evidence that it describes the dependency a program actually uses.

I like Go's bias toward code that another maintainer can understand. I want the same quality from tools that select dependencies or explain APIs. A tool should be able to identify the module and version behind a recommendation. Otherwise the maintainer has to reconstruct that decision from a search result, and the apparent convenience shifts work into review.

A path alone does not identify the dependency

The announcement illustrates a package path that can belong to a parent module or a nested module. The API returns an ambiguity error with candidates instead of choosing silently. For a client I would build, that error should become a request for more evidence. The project's selected module would be one possible source of that evidence. A user making a new dependency choice would need a different decision process.

That behavior is useful because discovery and identification answer different questions. Search can propose a package that might solve a problem. Identification establishes which implementation the tool is describing. I would keep the candidate list visible until the client has resolved it, especially in an automated workflow that may continue without another human reading every response.

I would also retain the resolved module path in the tool's output. Reporting only the import path would discard information the API required to answer the query. That loss could make a later investigation ambiguous again. A useful explanation should let a reviewer reproduce the same request with the same intended module.

Version selection belongs in the request

The beta API supports a version query parameter, including semantic versions and the default branch names main or master. The announcement says branch requests resolve to pseudo-versions and that omitting the parameter selects the latest tagged version. It does not describe support for arbitrary branch names.

For a maintenance tool, I would usually start with an explicit release. A query such as the following asks for the tagged version used in the announcement's package example, with module identity made explicit according to the beta schema.

curl -fsS 'https://pkg.go.dev/v1beta/package/github.com/google/go-cmp/cmp?module=github.com%2Fgoogle%2Fgo-cmp&version=v0.7.0'

The launch-day OpenAPI schema defines those package query parameters. It also defines fields for the resolved module and version in the response. I would check them before accepting the returned information into a report. The request records intent, while the response records what the service resolved.

A branch query would serve a different purpose in my workflow. It could help investigate development code, but I would record the resulting pseudo-version rather than preserve only the branch name. That is an application policy I would choose for reproducibility. A statement about the development branch needs enough context to distinguish it from a statement about a release.

This distinction also affects caching. I would avoid treating an omitted version as if it named a fixed release. Even when a tool caches a response, it needs a rule for when to resolve that moving request again. The concrete release version in the response gives the report a more useful identity than a label saying only that it queried the latest code.

Metadata retrieval can be selective

The launch-day schema lets a package request ask for documentation in text, HTML, or Markdown. Documentation is absent when the client does not request a format. Imports and licenses are optional too, and examples can accompany documentation. A module request can ask for a README and licenses separately from its basic metadata.

I would use those options to match the next decision the tool needs to make. A package inventory needs identity and perhaps a synopsis. An explanation of a function needs documentation and symbol information. Pulling full documentation into every discovery result would make a client process material it may never use. Conversely, a synopsis alone would be inadequate evidence for a detailed claim about behavior.

The package handler at the launch-day revision makes this selection concrete. It chooses data-loading fields from the requested options. It also rejects an examples request without a documentation format. That validation gives a client an actionable error instead of leaving it to guess whether omitted output means no examples exist.

I would mirror that distinction in the client result. A field that was not requested should remain distinguishable from an empty field that was requested. Those states can lead to different next steps. The first may justify a second request, while the second may be the information the client was looking for.

Discovery needs bounds and continuation handling

The same handler source sets limits for paginated results and a maximum search result count. In the search implementation, filtering occurs after retrieving candidates. The code explains why it may need a larger candidate set when a filter is present. A filtered search is therefore a service operation with defined bounds, not a promise to enumerate every relevant package in the ecosystem.

For a client producing an inventory, I would state which query it ran and whether it completed the available continuation sequence. A partial response can still be useful, but it should not become a claim of exhaustive coverage. That requirement matters more when the output informs a dependency review than when a human is browsing a few possible packages.

The schema exposes nextPageToken in paginated responses. The token implementation at that revision rejects expired continuation tokens after 48 hours. It also rejects malformed tokens and tokens with timestamps too far in the future. I would handle a continuation failure explicitly and avoid presenting a restarted query as if it completed the original traversal.

That is a practical consideration for scheduled tools. A process may pause between pages or resume after a failure. I would persist enough information to explain what it completed, while leaving the token opaque. Depending on the token's internal format would tie the client to implementation details that the public request does not require it to understand.

I would make the output preserve a distinction between the requested version and the resolved version throughout the workflow. A search result may start a new investigation, while a later query describes one selected release. If the tool merges those stages into a single record, a reviewer may be unable to tell whether its explanation still refers to the candidate originally returned. A test can deliberately return different versions at those stages and require the report to identify the change. That would verify the client's handling of evidence without assuming that a moving request remains fixed.

Vulnerability metadata needs an application decision

The beta schema includes a vulnerability endpoint for module or package paths. Its result describes an identifier and details, with a fixed version when available. That is useful input for a dependency report. I would still keep the retrieval of an advisory separate from a decision about a particular program's exposure.

For example, I would want a report to preserve the version it queried and the advisory identifier alongside its recommendation. A reviewer could then inspect the advisory and the project's use of the dependency. I would not reduce the result to a bare safe or unsafe label, since that would hide both the evidence and the assumptions used to interpret it.

The announcement provides a reference command-line client and explicitly says its interface may change. For a durable integration, I would put a small boundary around the beta HTTP contract and test the response handling there. The tests should include module ambiguity and continuation failures. I would also include a fixture where a request omits documentation, so that the rest of the tool cannot accidentally interpret unrequested data as evidence that documentation does not exist.