Angular has evolved significantly with the introduction of signals in version 16, bringing a more reactive and performant approach to state management. However, integrating Apollo GraphQL with Angular’s new signal-based paradigm has remained a challenge — until now.
The Problem
Apollo Angular works beautifully with RxJS observables, but modern Angular applications are increasingly adopting signals for their reactivity model. This creates friction when you need to use GraphQL data in signal-based components, forcing developers to write boilerplate code to bridge the gap between observables and signals.
Introducing apollo-angular-signal
apollo-angular-signal is a lightweight library that seamlessly converts Apollo GraphQL queries and subscriptions into Angular signals.
With just one function and a declarative component, you can transform your Apollo queries into native Angular signals and handle loading/error states elegantly.
Installation
npm install apollo-angular-signal
Key Features
1. Simple API
The library exposes a single function, gqlQuery(), that handles all the complexity.
import { gqlQuery } from 'apollo-angular-signal';
users = gqlQuery(
this.apollo.watchQuery({ query: GET_USERS }).valueChanges
);
2. Built-in State Management
No need to manually track loading states and errors.
The signal returns a structured result.
interface GqlSignalResult<T> {
data?: T;
loading: boolean;
hasError: boolean;
error?: unknown;
}
3. Declarative State Handling with GqlSignalStatus
The GqlSignalStatus component eliminates repetitive @if blocks for loading and error states.
It has display: contents in its styling, meaning it does not render any wrapper element in the DOM — the component itself has no visual impact. Inside, it only contains conditional logic to render the loading, error, or success templates based on the signal's value.
@Component({
imports: [GqlSignalStatus],
template: `
<gql-signal-status [gql]="users()">
<div gqlLoading>Loading users...</div>
<div gqlError>Failed to load users</div>
<ul>
@for (user of users().data?.users; track user.id) {
<li>{{ user.name }} - {{ user.email }}</li>
}
</ul>
</gql-signal-status>
`
})
export class UsersComponent {
private apollo = inject(Apollo);
users = gqlQuery<{ users: User[] }>(
this.apollo.watchQuery({ query: GET_USERS }).valueChanges
);
}
Benefits of GqlSignalStatus
-
Declarative — No more nested
@ifconditions - Reusable — Define loading/error templates once, use everywhere
- Flexible — Customize per component or set global defaults
- Clean — Separates concerns between data and presentation
4. Global Configuration
Set default templates for all your queries at once.
import { provideGqlSignalConfig } from 'apollo-angular-signal';
import { LoadingSpinnerComponent } from './loading-spinner.component';
import { ErrorAlertComponent } from './error-alert.component';
export const appConfig: ApplicationConfig = {
providers: [
provideGqlSignalConfig({
loadingDefaultTemplate: LoadingSpinnerComponent,
errorDefaultTemplate: ErrorAlertComponent
})
]
};
Now every GqlSignalStatus component automatically uses your custom loading spinner and error alert — no need to repeat them in every template.
5. Reactive Queries
The library supports reactive queries that automatically re-execute when dependencies change.
userId = signal('1');
user = gqlQuery(() => {
const id = this.userId();
if (!id) return null;
return this.apollo.watchQuery({
query: GET_USER,
variables: { id }
}).valueChanges;
});
When userId changes, the query automatically re-executes — no manual subscription management needed.
6. Subscription Support
GraphQL subscriptions work just as seamlessly.
messages = gqlQuery(
this.apollo.subscribe({
query: MESSAGE_SUBSCRIPTION
})
);
How It Works
Under the hood, the library leverages Angular’s effect system to:
- Subscribe to Apollo observables
- Update a writable signal with query results
- Automatically clean up subscriptions using
takeUntilDestroyed() - Handle reactive re-execution when dependencies change
For reactive queries, it uses Angular’s computed() to track signal dependencies and automatically manage subscription lifecycles.
The GqlSignalStatus component uses Angular's content projection to conditionally render loading, error, or success states based on the signal's current value, with support for both inline templates and global configuration.
Conclusion
- Type-Safe — Full TypeScript support with generics
- Zero Boilerplate — No manual subscription management
- Automatic Cleanup — Leverages Angular’s lifecycle management
- Reactive by Design — Works naturally with signal-based architectures
-
Declarative UI — Handle loading/error states elegantly with
GqlSignalStatus - Flexible Configuration — Per-component customization or global defaults
- Lightweight — Minimal bundle size impact
Links
npm install apollo-angular-signal
Top comments (0)