A modern, feature-rich testing suite tool for querying and debugging subgraph data quickly. Built with Next.js, TypeScript, and shadcn/ui.
- Multi-Subgraph Support: Manage multiple subgraphs with easy configuration
- Dynamic Query Management: Create, edit, and organize GraphQL queries per subgraph
- Parameter Extraction: Automatically extract and manage query parameters
- Custom Validation: Write JavaScript functions to validate query results
- Execution History: Track and review all query executions
- Modern UI: Clean, responsive interface with dark/light mode support
- Browser Storage: All data stored locally in your browser for privacy
- Code Editors: Professional GraphQL and JavaScript editors with syntax highlighting
- Node.js 18+
- npm or yarn
- The Graph Studio API keys
- Clone the repository:
git clone <repository-url>
cd subgraph-debugger- Install dependencies:
npm install- Set up environment variables:
cp example.env .env- Edit
.envand add your API keys:
MY_SUBGRAPH_API_KEY=your_actual_api_key_here
MARLIN_STAKING_API_KEY=your_actual_api_key_here- Start the development server:
npm run dev- Open http://localhost:3000 in your browser.
- Go to the "Subgraphs" tab
- Click "Add Subgraph"
- Fill in:
- Name: A descriptive name for your subgraph
- URL: The GraphQL endpoint URL from The Graph Studio
- API Key Variable: The environment variable name for your API key
- Copy the generated environment variable template to your
.envfile - Add your actual API key to the
.envfile
- Select a subgraph
- Go to the "Queries" tab
- Click "Add Query"
- Fill in:
- Query Name: A descriptive name for your query
- GraphQL Query: Your GraphQL query with parameters using
${parameterName}syntax - Validation Function (optional): JavaScript code to validate results
{
delegators(
where: { address: \${address} }
block: { number: \${blockNumber} }
) {
pendingRewards(where: { amount_gt: \${minAmount} }) {
amount
}
totalPendingReward
}
}Parameter Types:
- String parameters (like
address) are automatically quoted - Numeric parameters (like
blockNumber,amount_gt) are not quoted - Parameter types are automatically detected based on context
// Return true if validation passes, false otherwise
// The 'data' parameter contains the direct GraphQL response
// Use debug(name, value) to capture variables for inspection
const delegators = data.delegators;
if (!delegators || delegators.length === 0) {
return false;
}
const pendingRewards = delegators[0].pendingRewards;
if (!pendingRewards || pendingRewards.length === 0) {
return false;
}
// Capture debug variables
const amounts = pendingRewards.map((entry) => BigInt(entry.amount));
const totalSum = amounts.reduce((acc, val) => acc + val, 0n);
const totalPending = BigInt(delegators[0].totalPendingReward);
debug(
'individual_amounts',
amounts.map((a) => a.toString())
);
debug('total_sum', totalSum.toString());
debug('total_pending', totalPending.toString());
debug('comparison_result', totalSum === totalPending);
return totalSum === totalPending;- Go to the "Execute" tab
- Select a query to execute
- Fill in the parameter values
- Click "Execute Query"
- View results and validation status
- Check debug variables in validation results for detailed insights
- Go to the "History" tab
- Browse all executed queries
- View detailed results, parameters, and validation outcomes
- Delete individual entries or clear all history
The tool uses environment variables for API keys. Each subgraph gets its own environment variable:
- Variable format:
SUBGRAPH_NAME_API_KEY - Example:
MARLIN_STAKING_API_KEY=your_api_key_here
When writing validation functions, you can use the debug(name, value) function to capture variables for inspection. These variables will be displayed in the validation results, helping you understand what values were compared and why a validation passed or failed.
// Capture intermediate values
const amounts = data.delegators[0].pendingRewards.map((entry) =>
BigInt(entry.amount)
);
debug(
'individual_amounts',
amounts.map((a) => a.toString())
);
const totalSum = amounts.reduce((acc, val) => acc + val, 0n);
debug('total_sum', totalSum.toString());
const totalPending = BigInt(data.delegators[0].totalPendingReward);
debug('total_pending', totalPending.toString());
debug('comparison_result', totalSum === totalPending);
return totalSum === totalPending;The tool automatically detects parameter types based on their usage context:
Used for addresses, IDs, and text values:
where: { address: \${address} }Used for block numbers, amounts, limits, and counts:
block: { number: \${blockNumber} }
amount_gt: \${minAmount}
limit: \${count}The system automatically detects parameter types based on common GraphQL patterns:
block: {number: ...}→ numericamount_gt: ...→ numericlimit: ...→ numericfirst: ...→ numericskip: ...→ numericcount: ...→ numeric- All others → string
All data is stored locally in your browser's localStorage:
- Subgraph configurations
- Queries and parameters
- Execution history
- Validation functions
You can clear all data using the trash icon in the header.
The tool comes with two example queries for testing:
{
delegators(where: { address: \${address} }) {
pendingRewards(where: { amount_gt: 0 }) {
amount
}
totalPendingReward
}
}{
delegators(
where: { address: \${address} }
block: { number: \${blockNumber} }
) {
historicalRewardWithdrawl {
amount
}
totalRewardsClaimed
}
}- Framework: Next.js 15 with App Router
- Language: TypeScript
- Styling: Tailwind CSS
- UI Components: shadcn/ui
- State Management: React Query
- GraphQL: graphql-request
- Icons: Lucide React
src/
├── app/ # Next.js app directory
│ ├── layout.tsx # Root layout with providers
│ ├── page.tsx # Main dashboard page
│ └── providers.tsx # React Query provider
├── components/ # React components
│ ├── ui/ # shadcn/ui components
│ ├── subgraph-manager.tsx
│ ├── query-manager.tsx
│ ├── query-executor.tsx
│ ├── query-history.tsx
│ └── theme-toggle.tsx
└── lib/ # Utilities and types
├── types.ts # TypeScript interfaces
├── storage.ts # localStorage utilities
├── graphql.ts # GraphQL utilities
└── utils.ts # General utilities
npm run dev- Start development servernpm run build- Build for productionnpm run start- Start production servernpm run lint- Run ESLint
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
MIT License - see LICENSE file for details.