or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# @tanstack/eslint-plugin-query

1

2

@tanstack/eslint-plugin-query is an ESLint plugin specifically designed for TanStack Query applications. It provides a comprehensive set of linting rules to enforce best practices and prevent common pitfalls when using TanStack Query, helping developers avoid runtime errors and maintain consistent coding patterns.

3

4

## Package Information

5

6

- **Package Name**: @tanstack/eslint-plugin-query

7

- **Package Type**: npm

8

- **Language**: TypeScript

9

- **Installation**: `npm install @tanstack/eslint-plugin-query`

10

11

## Core Imports

12

13

```typescript

14

import queryPlugin from "@tanstack/eslint-plugin-query";

15

// Named exports also available:

16

import { Plugin } from "@tanstack/eslint-plugin-query";

17

```

18

19

For legacy configuration:

20

21

```javascript

22

const queryPlugin = require("@tanstack/eslint-plugin-query");

23

```

24

25

## Basic Usage

26

27

### Modern Flat Config (ESLint 9+)

28

29

```javascript

30

import queryPlugin from "@tanstack/eslint-plugin-query";

31

32

export default [

33

// Other configs...

34

...queryPlugin.configs["flat/recommended"]

35

];

36

```

37

38

### Legacy Config (ESLint 8)

39

40

```javascript

41

module.exports = {

42

plugins: ["@tanstack/query"],

43

extends: ["plugin:@tanstack/query/recommended"],

44

// Or configure individual rules:

45

rules: {

46

"@tanstack/query/exhaustive-deps": "error",

47

"@tanstack/query/no-rest-destructuring": "warn",

48

"@tanstack/query/stable-query-client": "error",

49

}

50

};

51

```

52

53

## Capabilities

54

55

### Plugin Structure

56

57

Main plugin object with rules and configurations.

58

59

```typescript { .api }

60

interface Plugin extends Omit<ESLint.Plugin, 'rules'> {

61

rules: Record<RuleKey, RuleModule<any, any, any>>;

62

configs: {

63

recommended: ESLint.ConfigData;

64

'flat/recommended': Array<Linter.Config>;

65

};

66

}

67

68

const plugin: Plugin;

69

export default plugin;

70

```

71

72

### Configuration Presets

73

74

Pre-configured rule sets for immediate use.

75

76

```typescript { .api }

77

// Legacy configuration format

78

interface RecommendedConfig {

79

plugins: string[];

80

rules: {

81

'@tanstack/query/exhaustive-deps': 'error';

82

'@tanstack/query/no-rest-destructuring': 'warn';

83

'@tanstack/query/stable-query-client': 'error';

84

'@tanstack/query/no-unstable-deps': 'error';

85

'@tanstack/query/infinite-query-property-order': 'error';

86

'@tanstack/query/no-void-query-fn': 'error';

87

'@tanstack/query/mutation-property-order': 'error';

88

};

89

}

90

91

// Modern flat configuration format

92

interface FlatRecommendedConfig extends Array<{

93

name: string;

94

plugins: Record<string, Plugin>;

95

rules: Record<string, string>;

96

}> {}

97

```

98

99

### ESLint Rules

100

101

Collection of seven specialized linting rules for TanStack Query applications.

102

103

#### Exhaustive Dependencies Rule

104

105

Ensures all dependencies used in queryFn are included in queryKey to prevent stale closure issues.

106

107

```typescript { .api }

108

// Rule: @tanstack/query/exhaustive-deps

109

// Severity: error

110

// Description: Exhaustive deps rule for useQuery

111

// Provides auto-fix suggestions for missing dependencies

112

```

113

114

**Usage Example:**

115

```typescript

116

// ❌ Bad - missing dependencies in queryKey

117

useQuery({

118

queryKey: ['user'],

119

queryFn: () => fetchUser(userId, settings), // userId and settings not in queryKey

120

});

121

122

// ✅ Good - all dependencies included

123

useQuery({

124

queryKey: ['user', userId, settings],

125

queryFn: () => fetchUser(userId, settings),

126

});

127

```

128

129

#### No Rest Destructuring Rule

130

131

Disallows rest destructuring in queries to prevent excessive re-renders.

132

133

```typescript { .api }

134

// Rule: @tanstack/query/no-rest-destructuring

135

// Severity: warn

136

// Description: Disallows rest destructuring in queries

137

```

138

139

**Usage Example:**

140

```typescript

141

// ❌ Bad - rest destructuring can cause issues

142

const { data, ...rest } = useQuery({ queryKey: ['user'], queryFn: fetchUser });

143

144

// ✅ Good - explicit destructuring

145

const { data, isLoading, error } = useQuery({ queryKey: ['user'], queryFn: fetchUser });

146

```

147

148

#### Stable Query Client Rule

149

150

Makes sure that QueryClient is stable to prevent unnecessary re-renders.

151

152

```typescript { .api }

153

// Rule: @tanstack/query/stable-query-client

154

// Severity: error

155

// Description: Makes sure that QueryClient is stable

156

```

157

158

**Usage Example:**

159

```typescript

160

// ❌ Bad - creating new QueryClient instance on each render

161

function App() {

162

return (

163

<QueryClientProvider client={new QueryClient()}>

164

<MyComponent />

165

</QueryClientProvider>

166

);

167

}

168

169

// ✅ Good - stable QueryClient instance

170

const queryClient = new QueryClient();

171

function App() {

172

return (

173

<QueryClientProvider client={queryClient}>

174

<MyComponent />

175

</QueryClientProvider>

176

);

177

}

178

```

179

180

#### No Unstable Dependencies Rule

181

182

Disallows putting the result of query hooks directly in a React hook dependency array to prevent infinite re-render loops.

183

184

```typescript { .api }

185

// Rule: @tanstack/query/no-unstable-deps

186

// Severity: error

187

// Description: Disallow putting the result of query hooks directly in a React hook dependency array

188

```

189

190

**Usage Example:**

191

```typescript

192

// ❌ Bad - using query result directly in dependency array

193

const { data: user } = useQuery({ queryKey: ['user'], queryFn: fetchUser });

194

useEffect(() => {

195

console.log('User changed');

196

}, [user]); // This causes infinite re-renders

197

198

// ✅ Good - use specific properties or data content

199

useEffect(() => {

200

console.log('User changed');

201

}, [user?.id]); // Only re-run when user ID changes

202

```

203

204

#### Infinite Query Property Order Rule

205

206

Ensures correct order of inference sensitive properties for infinite queries.

207

208

```typescript { .api }

209

// Rule: @tanstack/query/infinite-query-property-order

210

// Severity: error

211

// Description: Ensure correct order of inference sensitive properties for infinite queries

212

```

213

214

**Usage Example:**

215

```typescript

216

// ✅ Good - properties in correct order

217

useInfiniteQuery({

218

queryKey: ['posts'],

219

queryFn: fetchPosts,

220

initialPageParam: 0,

221

getNextPageParam: (lastPage) => lastPage.nextCursor,

222

});

223

```

224

225

#### No Void Query Function Rule

226

227

Ensures queryFn returns a non-undefined value to prevent runtime issues.

228

229

```typescript { .api }

230

// Rule: @tanstack/query/no-void-query-fn

231

// Severity: error

232

// Description: Ensures queryFn returns a non-undefined value

233

```

234

235

**Usage Example:**

236

```typescript

237

// ❌ Bad - query function returns void

238

useQuery({

239

queryKey: ['user'],

240

queryFn: () => { console.log('fetching'); }, // returns void

241

});

242

243

// ✅ Good - query function returns data

244

useQuery({

245

queryKey: ['user'],

246

queryFn: () => fetchUser(), // returns Promise<User>

247

});

248

```

249

250

#### Mutation Property Order Rule

251

252

Ensures correct order of inference-sensitive properties in useMutation().

253

254

```typescript { .api }

255

// Rule: @tanstack/query/mutation-property-order

256

// Severity: error

257

// Description: Ensure correct order of inference-sensitive properties in useMutation()

258

```

259

260

**Usage Example:**

261

```typescript

262

// ✅ Good - properties in correct order

263

useMutation({

264

mutationFn: updateUser,

265

onSuccess: (data) => {

266

queryClient.invalidateQueries({ queryKey: ['user'] });

267

},

268

onError: (error) => {

269

console.error('Update failed:', error);

270

},

271

});

272

```

273

274

## Types

275

276

```typescript { .api }

277

import type { ESLint, Linter } from 'eslint';

278

import type { RuleModule } from '@typescript-eslint/utils/ts-eslint';

279

280

type RuleKey = keyof typeof rules;

281

282

interface Plugin extends Omit<ESLint.Plugin, 'rules'> {

283

rules: Record<RuleKey, RuleModule<any, any, any>>;

284

configs: {

285

recommended: ESLint.ConfigData;

286

'flat/recommended': Array<Linter.Config>;

287

};

288

}

289

290

type ExtraRuleDocs = {

291

recommended: 'strict' | 'error' | 'warn';

292

}

293

```

294

295

## Framework Compatibility

296

297

This ESLint plugin works with all TanStack Query framework adapters and automatically detects the correct query hooks from:

298

299

- **React**: `@tanstack/react-query`

300

- **Vue**: `@tanstack/vue-query`

301

- **Solid**: `@tanstack/solid-query`

302

- **Svelte**: `@tanstack/svelte-query`

303

- **Angular**: `@tanstack/angular-query-experimental`

304

305

The plugin uses intelligent import detection and only applies rules to code that uses TanStack Query hooks.

306

307

## Error Handling

308

309

The plugin automatically detects TanStack Query imports and only applies rules to relevant code. Rules provide detailed error messages and auto-fix suggestions where possible. If you encounter false positives, ensure your TanStack Query imports follow standard patterns:

310

311

```typescript

312

// Supported import patterns

313

import { useQuery } from '@tanstack/react-query';

314

import { useQuery } from '@tanstack/vue-query';

315

import { useQuery } from '@tanstack/solid-query';

316

import { useQuery } from '@tanstack/svelte-query';

317

```

318

319

## TypeScript Integration

320

321

The plugin includes full TypeScript definitions and integrates seamlessly with TypeScript ESLint parser. When using TypeScript, the plugin can provide enhanced type-aware linting for improved accuracy.